Add KBOOT.
This commit is contained in:
147
apps/elftosb/common/AESCounter.h
Normal file
147
apps/elftosb/common/AESCounter.h
Normal file
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* File: AESCounter.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
#if !defined(_AESCounter_h_)
|
||||
#define _AESCounter_h_
|
||||
|
||||
#include <string.h>
|
||||
#include <iostream>
|
||||
#include "Random.h"
|
||||
|
||||
//! An AES-128 counter is 128 bits, or 16 bytes.
|
||||
typedef uint8_t aes128_counter_t[16];
|
||||
|
||||
/*!
|
||||
* \brief Base class for AESCounter<S>.
|
||||
*
|
||||
* This class implements some bigger, non-template methods used in the
|
||||
* AESCounter<S> templated subclass.
|
||||
*/
|
||||
class AESCounterBase
|
||||
{
|
||||
public:
|
||||
//! \brief Reads hex encoded data from \a stream.
|
||||
void _readFromStream(std::istream &stream, unsigned bytes, uint8_t *buffer);
|
||||
|
||||
//! \brief Writes hex encoded data to \a stream.
|
||||
void _writeToStream(std::ostream &stream, unsigned bytes, const uint8_t *buffer) const;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Generic AES Counter class.
|
||||
*
|
||||
* The template parameter \a S is the number of bits in the counter.
|
||||
*
|
||||
* The underlying counter type can be accessed like this: AESCounter<128>::counter_t
|
||||
*
|
||||
* When a counter instance is destroyed, it erases the counter data by setting it
|
||||
* to all zeroes.
|
||||
*
|
||||
* \todo Add a way to allow only counter sizes of 128, 192, and 256 bits.
|
||||
* \todo Find a cross platform way to prevent the counter data from being written
|
||||
* to the VM swapfile.
|
||||
*
|
||||
* AESCounter<128> counter = AESCounter<128>::readFromStream(s);
|
||||
*/
|
||||
template <int S>
|
||||
class AESCounter : public AESCounterBase
|
||||
{
|
||||
public:
|
||||
//! Type for this size of AES counter.
|
||||
typedef uint8_t counter_t[S / 8];
|
||||
|
||||
public:
|
||||
//! \brief Default constructor.
|
||||
//!
|
||||
//! Initializes the counter to 0.
|
||||
AESCounter() { memset(m_counter, 0, sizeof(m_counter)); }
|
||||
//! \brief Constructor taking a counter value reference.
|
||||
AESCounter(const counter_t &counter) { memcpy(m_counter, &counter, sizeof(m_counter)); }
|
||||
// \brief Constructor taking a counter value pointer.
|
||||
AESCounter(const counter_t *counter) { memcpy(m_counter, counter, sizeof(m_counter)); }
|
||||
//! \brief Constructor, reads counter from stream in hex format.
|
||||
AESCounter(std::istream &stream) { readFromStream(stream); }
|
||||
//! \brief Copy constructor.
|
||||
AESCounter(const AESCounter<S> &other) { memcpy(m_counter, other.m_counter, sizeof(m_counter)); }
|
||||
//! \brief Destructor.
|
||||
//!
|
||||
//! Sets the counter value to zero.
|
||||
~AESCounter() { memset(m_counter, 0, sizeof(m_counter)); }
|
||||
//! \brief Set to the counter to a randomly generated value.
|
||||
void randomize()
|
||||
{
|
||||
RandomNumberGenerator rng;
|
||||
rng.generateBlock(m_counter, sizeof(m_counter));
|
||||
}
|
||||
|
||||
//! \brief Reads the counter from a hex encoded data stream.
|
||||
void readFromStream(std::istream &stream)
|
||||
{
|
||||
_readFromStream(stream, S / 8, reinterpret_cast<uint8_t *>(&m_counter));
|
||||
}
|
||||
|
||||
//! \brief Writes the counter to a data stream in hex encoded format.
|
||||
void writeToStream(std::ostream &stream) const
|
||||
{
|
||||
_writeToStream(stream, S / 8, reinterpret_cast<const uint8_t *>(&m_counter));
|
||||
}
|
||||
|
||||
//! \brief Increments the counter by val
|
||||
void incrementCounter(unsigned val)
|
||||
{
|
||||
for (unsigned j = 0; j < val; j++)
|
||||
{
|
||||
for (unsigned i = sizeof(AESCounter<S>::counter_t) - 1, carry = 1; (i >= 0) && carry; i--)
|
||||
{
|
||||
carry = !++m_counter[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//! \name Counter accessors
|
||||
//@{
|
||||
inline const counter_t &getCounter() const { return m_counter; }
|
||||
inline void getCounter(counter_t *counter) const { memcpy(counter, m_counter, sizeof(m_counter)); }
|
||||
inline void setCounter(const counter_t &counter) { memcpy(m_counter, &counter, sizeof(m_counter)); }
|
||||
inline void setCounter(const counter_t *counter) { memcpy(m_counter, counter, sizeof(m_counter)); }
|
||||
inline void setCounter(const AESCounter<S> &counter) { memcpy(m_counter, counter.m_counter, sizeof(m_counter)); }
|
||||
//@}
|
||||
|
||||
//! \name Operators
|
||||
//@{
|
||||
const AESCounter<S> &operator=(const AESCounter<S> &counter)
|
||||
{
|
||||
setCounter(counter);
|
||||
return *this;
|
||||
}
|
||||
const AESCounter<S> &operator=(const counter_t &counter)
|
||||
{
|
||||
setCounter(counter);
|
||||
return *this;
|
||||
}
|
||||
const AESCounter<S> &operator=(const counter_t *counter)
|
||||
{
|
||||
setCounter(counter);
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator const counter_t &() const { return m_counter; }
|
||||
operator const counter_t *() const { return m_counter; }
|
||||
friend std::ostream &operator<<(std::ostream &os, const AESCounter<S> &counter)
|
||||
{
|
||||
counter.writeToStream(os);
|
||||
return os;
|
||||
}
|
||||
//@}
|
||||
|
||||
protected:
|
||||
counter_t m_counter; //!< The counter value.
|
||||
};
|
||||
|
||||
//! Standard type definition for an AES-128 counter.
|
||||
typedef AESCounter<128> AES128Counter;
|
||||
|
||||
#endif // _AESCounter_h_
|
||||
76
apps/elftosb/common/AESKey.cpp
Normal file
76
apps/elftosb/common/AESKey.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* File: AESKey.cpp
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
|
||||
#include "AESKey.h"
|
||||
#include <stdexcept>
|
||||
#include "smart_ptr.h"
|
||||
#include "HexValues.h"
|
||||
#include <ctype.h>
|
||||
|
||||
//! The data from the stream is expected to be hex encoded. Each two characters
|
||||
//! from the stream encode a single result byte. All non-hexadecimal characters
|
||||
//! are ignored, including newlines. Every two hexadecimal characters form
|
||||
//! an encoded byte. This is true even if the two characters representing the
|
||||
//! upper and lower nibbles are separated by whitespace or other characters.
|
||||
//!
|
||||
//! \post The stream read head is left pointing just after the last encoded byte.
|
||||
//!
|
||||
//! \param stream Input stream to read from.
|
||||
//! \param bytes Number of encoded bytes to read. This is the number of \e
|
||||
//! result bytes, not the count of bytes to read from the stream.
|
||||
//! \param[out] buffer Pointer to the buffer where decoded data is written.
|
||||
//!
|
||||
//! \exception std::runtime_error This exception will be thrown if less
|
||||
//! data than required is available from \a stream, or if some other
|
||||
//! error occurs while reading from \a stream.
|
||||
void AESKeyBase::_readFromStream(std::istream &stream, unsigned bytes, uint8_t *buffer)
|
||||
{
|
||||
char temp[2];
|
||||
char c;
|
||||
char n = 0;
|
||||
|
||||
while (bytes)
|
||||
{
|
||||
if (stream.get(c).fail())
|
||||
{
|
||||
throw std::runtime_error("not enough data in stream");
|
||||
}
|
||||
|
||||
if (isHexDigit(c))
|
||||
{
|
||||
temp[n++] = c;
|
||||
if (n == 2)
|
||||
{
|
||||
*buffer++ = hexByteToInt(temp);
|
||||
bytes--;
|
||||
n = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//! Key data is written to \a stream as a sequence of hex encoded octets, each two
|
||||
//! characters long. No spaces or newlines are inserted between the encoded octets
|
||||
//! or at the end of the sequence.
|
||||
//!
|
||||
//! \exception std::runtime_error Thrown if the \a stream reports an error while
|
||||
//! writing the key data.
|
||||
void AESKeyBase::_writeToStream(std::ostream &stream, unsigned bytes, const uint8_t *buffer)
|
||||
{
|
||||
const char hexChars[] = "0123456789ABCDEF";
|
||||
while (bytes--)
|
||||
{
|
||||
uint8_t thisByte = *buffer++;
|
||||
char byteString[2];
|
||||
byteString[0] = hexChars[(thisByte & 0xf0) >> 4];
|
||||
byteString[1] = hexChars[thisByte & 0x0f];
|
||||
if (stream.write(byteString, 2).bad())
|
||||
{
|
||||
throw std::runtime_error("error while writing to stream");
|
||||
}
|
||||
}
|
||||
}
|
||||
123
apps/elftosb/common/AESKey.h
Normal file
123
apps/elftosb/common/AESKey.h
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* File: AESKey.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
#if !defined(_AESKey_h_)
|
||||
#define _AESKey_h_
|
||||
|
||||
#include "stdafx.h"
|
||||
#include <string.h>
|
||||
#include <iostream>
|
||||
#include "Random.h"
|
||||
|
||||
//! An AES-128 key is 128 bits, or 16 bytes.
|
||||
typedef uint8_t aes128_key_t[16];
|
||||
|
||||
/*!
|
||||
* \brief Base class for AESKey<S>.
|
||||
*
|
||||
* This class implements some bigger, non-template methods used in the
|
||||
* AESKey<S> templated subclass.
|
||||
*/
|
||||
class AESKeyBase
|
||||
{
|
||||
public:
|
||||
//! \brief Reads hex encoded data from \a stream.
|
||||
void _readFromStream(std::istream &stream, unsigned bytes, uint8_t *buffer);
|
||||
|
||||
//! \brief Writes hex encoded data to \a stream.
|
||||
void _writeToStream(std::ostream &stream, unsigned bytes, const uint8_t *buffer);
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Generic AES key class.
|
||||
*
|
||||
* The template parameter \a S is the number of bits in the key.
|
||||
*
|
||||
* The underlying key type can be accessed like this: AESKey<128>::key_t
|
||||
*
|
||||
* When a key instance is destroyed, it erases the key data by setting it
|
||||
* to all zeroes.
|
||||
*
|
||||
* \todo Add a way to allow only key sizes of 128, 192, and 256 bits.
|
||||
* \todo Find a cross platform way to prevent the key data from being written
|
||||
* to the VM swapfile.
|
||||
*
|
||||
* AESKey<128> key = AESKey<128>::readFromStream(s);
|
||||
*/
|
||||
template <int S>
|
||||
class AESKey : public AESKeyBase
|
||||
{
|
||||
public:
|
||||
//! Type for this size of AES key.
|
||||
typedef uint8_t key_t[S / 8];
|
||||
|
||||
public:
|
||||
//! \brief Default constructor.
|
||||
//!
|
||||
//! Initializes the key to 0.
|
||||
AESKey() { memset(m_key, 0, sizeof(m_key)); }
|
||||
//! \brief Constructor taking a key value reference.
|
||||
AESKey(const key_t &key) { memcpy(m_key, &key, sizeof(m_key)); }
|
||||
// \brief Constructor taking a key value pointer.
|
||||
AESKey(const key_t *key) { memcpy(m_key, key, sizeof(m_key)); }
|
||||
//! \brief Constructor, reads key from stream in hex format.
|
||||
AESKey(std::istream &stream) { readFromStream(stream); }
|
||||
//! \brief Copy constructor.
|
||||
AESKey(const AESKey<S> &other) { memcpy(m_key, other.m_key, sizeof(m_key)); }
|
||||
//! \brief Destructor.
|
||||
//!
|
||||
//! Sets the key value to zero.
|
||||
~AESKey() { memset(m_key, 0, sizeof(m_key)); }
|
||||
//! \brief Set to the key to a randomly generated value.
|
||||
void randomize()
|
||||
{
|
||||
RandomNumberGenerator rng;
|
||||
rng.generateBlock(m_key, sizeof(m_key));
|
||||
}
|
||||
|
||||
//! \brief Reads the key from a hex encoded data stream.
|
||||
void readFromStream(std::istream &stream) { _readFromStream(stream, S / 8, reinterpret_cast<uint8_t *>(&m_key)); }
|
||||
//! \brief Writes the key to a data stream in hex encoded format.
|
||||
void writeToStream(std::ostream &stream) { _writeToStream(stream, S / 8, reinterpret_cast<uint8_t *>(&m_key)); }
|
||||
//! \name Key accessors
|
||||
//@{
|
||||
inline const key_t &getKey() const { return m_key; }
|
||||
inline void getKey(key_t *key) const { memcpy(key, m_key, sizeof(m_key)); }
|
||||
inline void setKey(const key_t &key) { memcpy(m_key, &key, sizeof(m_key)); }
|
||||
inline void setKey(const key_t *key) { memcpy(m_key, key, sizeof(m_key)); }
|
||||
inline void setKey(const AESKey<S> &key) { memcpy(m_key, key.m_key, sizeof(m_key)); }
|
||||
//@}
|
||||
|
||||
//! \name Operators
|
||||
//@{
|
||||
const AESKey<S> &operator=(const AESKey<S> &key)
|
||||
{
|
||||
setKey(key);
|
||||
return *this;
|
||||
}
|
||||
const AESKey<S> &operator=(const key_t &key)
|
||||
{
|
||||
setKey(key);
|
||||
return *this;
|
||||
}
|
||||
const AESKey<S> &operator=(const key_t *key)
|
||||
{
|
||||
setKey(key);
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator const key_t &() const { return m_key; }
|
||||
operator const key_t *() const { return m_key; }
|
||||
//@}
|
||||
|
||||
protected:
|
||||
key_t m_key; //!< The key value.
|
||||
};
|
||||
|
||||
//! Standard type definition for an AES-128 key.
|
||||
typedef AESKey<128> AES128Key;
|
||||
|
||||
#endif // _AESKey_h_
|
||||
122
apps/elftosb/common/Blob.cpp
Normal file
122
apps/elftosb/common/Blob.cpp
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* File: Blob.cpp
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
|
||||
#include "Blob.h"
|
||||
#include <stdexcept>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
Blob::Blob()
|
||||
: m_data(0)
|
||||
, m_length(0)
|
||||
{
|
||||
}
|
||||
|
||||
//! Makes a local copy of the \a data argument.
|
||||
//!
|
||||
Blob::Blob(const uint8_t *data, unsigned length)
|
||||
: m_data(0)
|
||||
, m_length(length)
|
||||
{
|
||||
m_data = reinterpret_cast<uint8_t *>(malloc(length));
|
||||
memcpy(m_data, data, length);
|
||||
}
|
||||
|
||||
//! Makes a local copy of the data owned by \a other.
|
||||
//!
|
||||
Blob::Blob(const Blob &other)
|
||||
: m_data(0)
|
||||
, m_length(other.m_length)
|
||||
{
|
||||
m_data = reinterpret_cast<uint8_t *>(malloc(m_length));
|
||||
memcpy(m_data, other.m_data, m_length);
|
||||
}
|
||||
|
||||
//! Disposes of the binary data associated with this object.
|
||||
Blob::~Blob()
|
||||
{
|
||||
if (m_data)
|
||||
{
|
||||
free(m_data);
|
||||
}
|
||||
}
|
||||
|
||||
//! Copies \a data onto the blob's data. The blob does not assume ownership
|
||||
//! of \a data.
|
||||
//!
|
||||
//! \param data Pointer to a buffer containing the data which will be copied
|
||||
//! into the blob.
|
||||
//! \param length Number of bytes pointed to by \a data.
|
||||
void Blob::setData(const uint8_t *data, unsigned length)
|
||||
{
|
||||
setLength(length);
|
||||
memcpy(m_data, data, length);
|
||||
}
|
||||
|
||||
//! Sets the #m_length member variable to \a length and resizes #m_data to
|
||||
//! the new length. The contents of #m_data past any previous contents are undefined.
|
||||
//! If the new \a length is 0 then the data will be freed and a subsequent call
|
||||
//! to getData() will return NULL.
|
||||
//!
|
||||
//! \param length New length of the blob's data in bytes.
|
||||
void Blob::setLength(unsigned length)
|
||||
{
|
||||
if (length == 0)
|
||||
{
|
||||
clear();
|
||||
return;
|
||||
}
|
||||
|
||||
// Allocate new block.
|
||||
if (!m_data)
|
||||
{
|
||||
m_data = reinterpret_cast<uint8_t *>(malloc(length));
|
||||
if (!m_data)
|
||||
{
|
||||
throw std::runtime_error("failed to allocate memory");
|
||||
}
|
||||
}
|
||||
// Reallocate previous block.
|
||||
else
|
||||
{
|
||||
void *newBlob = realloc(m_data, length);
|
||||
if (!newBlob)
|
||||
{
|
||||
throw std::runtime_error("failed to reallocate memory");
|
||||
}
|
||||
m_data = reinterpret_cast<uint8_t *>(newBlob);
|
||||
}
|
||||
|
||||
// Set length.
|
||||
m_length = length;
|
||||
}
|
||||
|
||||
void Blob::append(const uint8_t *newData, unsigned newDataLength)
|
||||
{
|
||||
unsigned oldLength = m_length;
|
||||
|
||||
setLength(m_length + newDataLength);
|
||||
|
||||
memcpy(m_data + oldLength, newData, newDataLength);
|
||||
}
|
||||
|
||||
void Blob::clear()
|
||||
{
|
||||
if (m_data)
|
||||
{
|
||||
free(m_data);
|
||||
m_data = NULL;
|
||||
}
|
||||
|
||||
m_length = 0;
|
||||
}
|
||||
|
||||
void Blob::relinquish()
|
||||
{
|
||||
m_data = NULL;
|
||||
m_length = 0;
|
||||
}
|
||||
69
apps/elftosb/common/Blob.h
Normal file
69
apps/elftosb/common/Blob.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* File: Blob.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
#if !defined(_Blob_h_)
|
||||
#define _Blob_h_
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
/*!
|
||||
* \brief Manages a binary object of arbitrary length.
|
||||
*
|
||||
* The data block is allocated with malloc() instead of the new
|
||||
* operator so that we can use realloc() to resize it.
|
||||
*/
|
||||
class Blob
|
||||
{
|
||||
public:
|
||||
//! \brief Default constructor.
|
||||
Blob();
|
||||
|
||||
//! \brief Constructor.
|
||||
Blob(const uint8_t *data, unsigned length);
|
||||
|
||||
//! \brief Copy constructor.
|
||||
Blob(const Blob &other);
|
||||
|
||||
//! \brief Destructor.
|
||||
virtual ~Blob();
|
||||
|
||||
//! \name Operations
|
||||
//@{
|
||||
//! \brief Replaces the blob's data.
|
||||
void setData(const uint8_t *data, unsigned length);
|
||||
|
||||
//! \brief Change the size of the blob's data.
|
||||
void setLength(unsigned length);
|
||||
|
||||
//! \brief Adds data to the end of the blob.
|
||||
void append(const uint8_t *newData, unsigned newDataLength);
|
||||
|
||||
//! \brief Disposes of the data.
|
||||
void clear();
|
||||
|
||||
//! \brief Tell the blob that it no longer owns its data.
|
||||
void relinquish();
|
||||
//@}
|
||||
|
||||
//! \name Accessors
|
||||
//@{
|
||||
uint8_t *getData() { return m_data; }
|
||||
const uint8_t *getData() const { return m_data; }
|
||||
unsigned getLength() const { return m_length; }
|
||||
//@}
|
||||
|
||||
//! \name Operators
|
||||
//@{
|
||||
operator uint8_t *() { return m_data; }
|
||||
operator const uint8_t *() const { return m_data; }
|
||||
//@}
|
||||
|
||||
protected:
|
||||
uint8_t *m_data; //!< The binary data held by this object.
|
||||
unsigned m_length; //!< Number of bytes pointed to by #m_data.
|
||||
};
|
||||
|
||||
#endif // _Blob_h_
|
||||
50
apps/elftosb/common/BootImage.h
Normal file
50
apps/elftosb/common/BootImage.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* File: BootImage.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
#if !defined(_BootImage_h_)
|
||||
#define _BootImage_h_
|
||||
|
||||
#include <iostream>
|
||||
#include "Version.h"
|
||||
|
||||
namespace elftosb
|
||||
{
|
||||
/*!
|
||||
* \brief Abstract base class for all boot image format classes.
|
||||
*
|
||||
* Provides virtual methods for all of the common features between different
|
||||
* boot image formats. These are the product and component version numbers
|
||||
* and the drive tag.
|
||||
*
|
||||
* Also provided is the virtual method writeToStream() that lets the caller
|
||||
* stream out the boot image without knowing the underlying format type.
|
||||
*/
|
||||
class BootImage
|
||||
{
|
||||
public:
|
||||
//! \brief Constructor.
|
||||
BootImage() {}
|
||||
//! \brief Destructor.
|
||||
virtual ~BootImage() {}
|
||||
//! \name Versions
|
||||
//@{
|
||||
virtual void setProductVersion(const version_t &version) = 0;
|
||||
virtual void setComponentVersion(const version_t &version) = 0;
|
||||
//@}
|
||||
|
||||
//! \brief Specify the drive tag to be set in the output file header.
|
||||
virtual void setDriveTag(uint16_t tag) = 0;
|
||||
|
||||
//! \brief Returns a string containing the preferred file extension for image format.
|
||||
virtual std::string getFileExtension() const = 0;
|
||||
|
||||
//! \brief Write the boot image to an output stream.
|
||||
virtual void writeToStream(std::ostream &stream) = 0;
|
||||
};
|
||||
|
||||
}; // namespace elftosb
|
||||
|
||||
#endif // _BootImage_h_
|
||||
244
apps/elftosb/common/DataSource.cpp
Normal file
244
apps/elftosb/common/DataSource.cpp
Normal file
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
* File: DataSource.cpp
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
|
||||
#include "DataSource.h"
|
||||
#include "DataTarget.h"
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace elftosb;
|
||||
|
||||
#pragma mark *** DataSource::PatternSegment ***
|
||||
|
||||
DataSource::PatternSegment::PatternSegment(DataSource &source)
|
||||
: DataSource::Segment(source)
|
||||
, m_pattern()
|
||||
{
|
||||
}
|
||||
|
||||
DataSource::PatternSegment::PatternSegment(DataSource &source, const SizedIntegerValue &pattern)
|
||||
: DataSource::Segment(source)
|
||||
, m_pattern(pattern)
|
||||
{
|
||||
}
|
||||
|
||||
DataSource::PatternSegment::PatternSegment(DataSource &source, uint8_t pattern)
|
||||
: DataSource::Segment(source)
|
||||
, m_pattern(static_cast<uint8_t>(pattern))
|
||||
{
|
||||
}
|
||||
|
||||
DataSource::PatternSegment::PatternSegment(DataSource &source, uint16_t pattern)
|
||||
: DataSource::Segment(source)
|
||||
, m_pattern(static_cast<uint16_t>(pattern))
|
||||
{
|
||||
}
|
||||
|
||||
DataSource::PatternSegment::PatternSegment(DataSource &source, uint32_t pattern)
|
||||
: DataSource::Segment(source)
|
||||
, m_pattern(static_cast<uint32_t>(pattern))
|
||||
{
|
||||
}
|
||||
|
||||
unsigned DataSource::PatternSegment::getData(unsigned offset, unsigned maxBytes, uint8_t *buffer)
|
||||
{
|
||||
memset(buffer, 0, maxBytes);
|
||||
|
||||
return maxBytes;
|
||||
}
|
||||
|
||||
//! The pattern segment's length is a function of the data target. If the
|
||||
//! target is bounded, then the segment's length is simply the target's
|
||||
//! length. Otherwise, if no target has been set or the target is unbounded,
|
||||
//! then the length returned is 0.
|
||||
unsigned DataSource::PatternSegment::getLength()
|
||||
{
|
||||
DataTarget *target = m_source.getTarget();
|
||||
if (!target)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t length;
|
||||
if (target->isBounded())
|
||||
{
|
||||
length = target->getEndAddress() - target->getBeginAddress();
|
||||
}
|
||||
else
|
||||
{
|
||||
length = m_pattern.getSize();
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
#pragma mark *** PatternSource ***
|
||||
|
||||
PatternSource::PatternSource()
|
||||
: DataSource()
|
||||
, DataSource::PatternSegment((DataSource &)*this)
|
||||
{
|
||||
}
|
||||
|
||||
PatternSource::PatternSource(const SizedIntegerValue &value)
|
||||
: DataSource()
|
||||
, DataSource::PatternSegment((DataSource &)*this, value)
|
||||
{
|
||||
}
|
||||
|
||||
#pragma mark *** UnmappedDataSource ***
|
||||
|
||||
UnmappedDataSource::UnmappedDataSource()
|
||||
: DataSource()
|
||||
, DataSource::Segment((DataSource &)*this)
|
||||
, m_data()
|
||||
, m_length(0)
|
||||
{
|
||||
}
|
||||
|
||||
UnmappedDataSource::UnmappedDataSource(const uint8_t *data, unsigned length)
|
||||
: DataSource()
|
||||
, DataSource::Segment((DataSource &)*this)
|
||||
, m_data()
|
||||
, m_length(0)
|
||||
{
|
||||
setData(data, length);
|
||||
}
|
||||
|
||||
//! Makes a copy of \a data that is freed when the data source is
|
||||
//! destroyed. The caller does not have to maintain \a data after this call
|
||||
//! returns.
|
||||
void UnmappedDataSource::setData(const uint8_t *data, unsigned length)
|
||||
{
|
||||
m_data.safe_delete();
|
||||
|
||||
uint8_t *dataCopy = new uint8_t[length];
|
||||
memcpy(dataCopy, data, length);
|
||||
m_data = dataCopy;
|
||||
m_length = length;
|
||||
}
|
||||
|
||||
unsigned UnmappedDataSource::getData(unsigned offset, unsigned maxBytes, uint8_t *buffer)
|
||||
{
|
||||
assert(offset < m_length);
|
||||
unsigned copyBytes = std::min<unsigned>(m_length - offset, maxBytes);
|
||||
memcpy(buffer, m_data.get(), copyBytes);
|
||||
return copyBytes;
|
||||
}
|
||||
|
||||
#pragma mark *** MemoryImageDataSource ***
|
||||
|
||||
MemoryImageDataSource::MemoryImageDataSource(StExecutableImage *image)
|
||||
: DataSource()
|
||||
, m_image(image)
|
||||
{
|
||||
// reserve enough room for all segments
|
||||
m_segments.reserve(m_image->getRegionCount());
|
||||
}
|
||||
|
||||
MemoryImageDataSource::~MemoryImageDataSource()
|
||||
{
|
||||
segment_array_t::iterator it = m_segments.begin();
|
||||
for (; it != m_segments.end(); ++it)
|
||||
{
|
||||
// delete this segment if it has been created
|
||||
if (*it)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned MemoryImageDataSource::getSegmentCount()
|
||||
{
|
||||
return m_image->getRegionCount();
|
||||
}
|
||||
|
||||
DataSource::Segment *MemoryImageDataSource::getSegmentAt(unsigned index)
|
||||
{
|
||||
// return previously created segment
|
||||
if (index < m_segments.size() && m_segments[index])
|
||||
{
|
||||
return m_segments[index];
|
||||
}
|
||||
|
||||
// extend array out to this index
|
||||
if (index >= m_segments.size() && index < m_image->getRegionCount())
|
||||
{
|
||||
m_segments.resize(index + 1, NULL);
|
||||
}
|
||||
|
||||
// create the new segment object
|
||||
DataSource::Segment *newSegment;
|
||||
const StExecutableImage::MemoryRegion ®ion = m_image->getRegionAtIndex(index);
|
||||
if (region.m_type == StExecutableImage::TEXT_REGION)
|
||||
{
|
||||
newSegment = new TextSegment(*this, m_image, index);
|
||||
}
|
||||
else if (region.m_type == StExecutableImage::FILL_REGION)
|
||||
{
|
||||
newSegment = new FillSegment(*this, m_image, index);
|
||||
}
|
||||
|
||||
m_segments[index] = newSegment;
|
||||
return newSegment;
|
||||
}
|
||||
|
||||
#pragma mark *** MemoryImageDataSource::TextSegment ***
|
||||
|
||||
MemoryImageDataSource::TextSegment::TextSegment(MemoryImageDataSource &source, StExecutableImage *image, unsigned index)
|
||||
: DataSource::Segment(source)
|
||||
, m_image(image)
|
||||
, m_index(index)
|
||||
{
|
||||
}
|
||||
|
||||
unsigned MemoryImageDataSource::TextSegment::getData(unsigned offset, unsigned maxBytes, uint8_t *buffer)
|
||||
{
|
||||
const StExecutableImage::MemoryRegion ®ion = m_image->getRegionAtIndex(m_index);
|
||||
assert(region.m_type == StExecutableImage::TEXT_REGION);
|
||||
|
||||
unsigned copyBytes = std::min<unsigned>(region.m_length - offset, maxBytes);
|
||||
memcpy(buffer, ®ion.m_data[offset], copyBytes);
|
||||
|
||||
return copyBytes;
|
||||
}
|
||||
|
||||
unsigned MemoryImageDataSource::TextSegment::getLength()
|
||||
{
|
||||
const StExecutableImage::MemoryRegion ®ion = m_image->getRegionAtIndex(m_index);
|
||||
return region.m_length;
|
||||
}
|
||||
|
||||
uint32_t MemoryImageDataSource::TextSegment::getBaseAddress()
|
||||
{
|
||||
const StExecutableImage::MemoryRegion ®ion = m_image->getRegionAtIndex(m_index);
|
||||
return region.m_address;
|
||||
}
|
||||
|
||||
#pragma mark *** MemoryImageDataSource::FillSegment ***
|
||||
|
||||
MemoryImageDataSource::FillSegment::FillSegment(MemoryImageDataSource &source, StExecutableImage *image, unsigned index)
|
||||
: DataSource::PatternSegment(source)
|
||||
, m_image(image)
|
||||
, m_index(index)
|
||||
{
|
||||
SizedIntegerValue zero(0, kWordSize);
|
||||
setPattern(zero);
|
||||
}
|
||||
|
||||
unsigned MemoryImageDataSource::FillSegment::getLength()
|
||||
{
|
||||
const StExecutableImage::MemoryRegion ®ion = m_image->getRegionAtIndex(m_index);
|
||||
return region.m_length;
|
||||
}
|
||||
|
||||
uint32_t MemoryImageDataSource::FillSegment::getBaseAddress()
|
||||
{
|
||||
const StExecutableImage::MemoryRegion ®ion = m_image->getRegionAtIndex(m_index);
|
||||
return region.m_address;
|
||||
}
|
||||
300
apps/elftosb/common/DataSource.h
Normal file
300
apps/elftosb/common/DataSource.h
Normal file
@@ -0,0 +1,300 @@
|
||||
/*
|
||||
* File: DataSource.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
#if !defined(_DataSource_h_)
|
||||
#define _DataSource_h_
|
||||
|
||||
#include <vector>
|
||||
#include "Value.h"
|
||||
#include "smart_ptr.h"
|
||||
#include "StExecutableImage.h"
|
||||
|
||||
namespace elftosb
|
||||
{
|
||||
// Forward declaration
|
||||
class DataTarget;
|
||||
|
||||
/*!
|
||||
* \brief Abstract base class for data sources.
|
||||
*
|
||||
* Data sources represent any sort of data that can be placed or loaded
|
||||
* into a target region. Sources may be a single blob of data read from
|
||||
* a file or may consist of many segments.
|
||||
*
|
||||
* The three most important features of data sources are:
|
||||
* - Sources may be multi-segmented.
|
||||
* - Sources and/or segments can have a "natural" or default target location.
|
||||
* - The target for a source may be taken into consideration when the source
|
||||
* describes itself.
|
||||
*/
|
||||
class DataSource
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* \brief Discrete, contiguous part of the source's data.
|
||||
*
|
||||
* This class is purely abstract and subclasses of DataSource are expected
|
||||
* to subclass it to implement a segment particular to their needs.
|
||||
*/
|
||||
class Segment
|
||||
{
|
||||
public:
|
||||
//! \brief Default constructor.
|
||||
Segment(DataSource &source)
|
||||
: m_source(source)
|
||||
{
|
||||
}
|
||||
|
||||
//! \brief Destructor.
|
||||
virtual ~Segment() {}
|
||||
//! \brief Gets all or a portion of the segment's data.
|
||||
//!
|
||||
//! The data is copied into \a buffer. Up to \a maxBytes bytes may be
|
||||
//! copied, so \a buffer must be at least that large.
|
||||
//!
|
||||
//! \param offset Index of the first byte to start copying from.
|
||||
//! \param maxBytes The maximum number of bytes that can be returned. \a buffer
|
||||
//! must be at least this large.
|
||||
//! \param buffer Pointer to buffer where the data is copied.
|
||||
//! \return The number of bytes copied into \a buffer.
|
||||
virtual unsigned getData(unsigned offset, unsigned maxBytes, uint8_t *buffer) = 0;
|
||||
|
||||
//! \brief Gets the length of the segment's data.
|
||||
virtual unsigned getLength() = 0;
|
||||
|
||||
//! \brief Returns whether the segment has an associated address.
|
||||
virtual bool hasNaturalLocation() = 0;
|
||||
|
||||
//! \brief Returns the address associated with the segment.
|
||||
virtual uint32_t getBaseAddress() { return 0; }
|
||||
protected:
|
||||
DataSource &m_source; //!< The data source to which this segment belongs.
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief This is a special type of segment containing a repeating pattern.
|
||||
*
|
||||
* By default the segment doesn't have a specific length or data. The length depends
|
||||
* on the target's address range. And the data is just the pattern, repeated
|
||||
* many times. In addition, pattern segments do not have a natural location.
|
||||
*
|
||||
* Calling code should look for instances of PatternSegment and handle them
|
||||
* as special cases that can be optimized.
|
||||
*/
|
||||
class PatternSegment : public Segment
|
||||
{
|
||||
public:
|
||||
//! \brief Default constructor.
|
||||
PatternSegment(DataSource &source);
|
||||
|
||||
//! \brief Constructor taking a fill pattern.
|
||||
PatternSegment(DataSource &source, const SizedIntegerValue &pattern);
|
||||
|
||||
//! \brief Constructor taking a byte fill pattern.
|
||||
PatternSegment(DataSource &source, uint8_t pattern);
|
||||
|
||||
//! \brief Constructor taking a half-word fill pattern.
|
||||
PatternSegment(DataSource &source, uint16_t pattern);
|
||||
|
||||
//! \brief Constructor taking a word fill pattern.
|
||||
PatternSegment(DataSource &source, uint32_t pattern);
|
||||
|
||||
//! \name Segment methods
|
||||
//@{
|
||||
//! \brief Pattern segments have no natural address.
|
||||
virtual bool hasNaturalLocation() { return false; }
|
||||
//! \brief Performs a pattern fill into the \a buffer.
|
||||
virtual unsigned getData(unsigned offset, unsigned maxBytes, uint8_t *buffer);
|
||||
|
||||
//! \brief Returns a length based on the data target's address range.
|
||||
virtual unsigned getLength();
|
||||
//@}
|
||||
|
||||
//! \name Pattern accessors
|
||||
//@{
|
||||
//! \brief Assigns a new fill pattern.
|
||||
inline void setPattern(const SizedIntegerValue &newPattern) { m_pattern = newPattern; }
|
||||
//! \brief Return the fill pattern for the segment.
|
||||
inline SizedIntegerValue &getPattern() { return m_pattern; }
|
||||
//! \brief Assignment operator, sets the pattern value and length.
|
||||
PatternSegment &operator=(const SizedIntegerValue &value)
|
||||
{
|
||||
m_pattern = value;
|
||||
return *this;
|
||||
}
|
||||
//@}
|
||||
|
||||
protected:
|
||||
SizedIntegerValue m_pattern; //!< The fill pattern.
|
||||
};
|
||||
|
||||
public:
|
||||
//! \brief Default constructor.
|
||||
DataSource()
|
||||
: m_target(0)
|
||||
{
|
||||
}
|
||||
|
||||
//! \brief Destructor.
|
||||
virtual ~DataSource() {}
|
||||
//! \name Data target
|
||||
//@{
|
||||
//! \brief Sets the associated data target.
|
||||
inline void setTarget(DataTarget *target) { m_target = target; }
|
||||
//! \brief Gets the associated data target.
|
||||
inline DataTarget *getTarget() const { return m_target; }
|
||||
//@}
|
||||
|
||||
//! \name Segments
|
||||
//@{
|
||||
//! \brief Returns the number of segments in this data source.
|
||||
virtual unsigned getSegmentCount() = 0;
|
||||
|
||||
//! \brief Returns segment number \a index of the data source.
|
||||
virtual Segment *getSegmentAt(unsigned index) = 0;
|
||||
//@}
|
||||
|
||||
protected:
|
||||
DataTarget *m_target; //!< Corresponding target for this source.
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Data source for a repeating pattern.
|
||||
*
|
||||
* The pattern is represented by a SizedIntegerValue object. Thus the pattern
|
||||
* can be either byte, half-word, or word sized.
|
||||
*
|
||||
* This data source has only one segment, and the PatternSource instance acts
|
||||
* as its own single segment.
|
||||
*/
|
||||
class PatternSource : public DataSource, public DataSource::PatternSegment
|
||||
{
|
||||
public:
|
||||
//! \brief Default constructor.
|
||||
PatternSource();
|
||||
|
||||
//! \brief Constructor taking the pattern value.
|
||||
PatternSource(const SizedIntegerValue &value);
|
||||
|
||||
//! \brief There is only one segment.
|
||||
virtual unsigned getSegmentCount() { return 1; }
|
||||
//! \brief Returns this object, as it is its own segment.
|
||||
virtual DataSource::Segment *getSegmentAt(unsigned index) { return this; }
|
||||
//! \brief Assignment operator, sets the pattern value and length.
|
||||
PatternSource &operator=(const SizedIntegerValue &value)
|
||||
{
|
||||
setPattern(value);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Data source for data that is not memory mapped (has no natural address).
|
||||
*
|
||||
* This data source can only manage a single block of data, which has no
|
||||
* associated address. It acts as its own Segment.
|
||||
*/
|
||||
class UnmappedDataSource : public DataSource, public DataSource::Segment
|
||||
{
|
||||
public:
|
||||
//! \brief Default constructor.
|
||||
UnmappedDataSource();
|
||||
|
||||
//! \brief Constructor taking the data, which is copied.
|
||||
UnmappedDataSource(const uint8_t *data, unsigned length);
|
||||
|
||||
//! \brief Sets the source's data.
|
||||
void setData(const uint8_t *data, unsigned length);
|
||||
|
||||
//! \brief There is only one segment.
|
||||
virtual unsigned getSegmentCount() { return 1; }
|
||||
//! \brief Returns this object, as it is its own segment.
|
||||
virtual DataSource::Segment *getSegmentAt(unsigned index) { return this; }
|
||||
//! \name Segment methods
|
||||
//@{
|
||||
//! \brief Unmapped data sources have no natural address.
|
||||
virtual bool hasNaturalLocation() { return false; }
|
||||
//! \brief Copies a portion of the data into \a buffer.
|
||||
virtual unsigned getData(unsigned offset, unsigned maxBytes, uint8_t *buffer);
|
||||
|
||||
//! \brief Returns the number of bytes of data managed by the source.
|
||||
virtual unsigned getLength() { return m_length; }
|
||||
//@}
|
||||
|
||||
protected:
|
||||
smart_array_ptr<uint8_t> m_data; //!< The data.
|
||||
unsigned m_length; //!< Byte count of the data.
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Data source that takes its data from an executable image.
|
||||
*
|
||||
* \see StExecutableImage
|
||||
*/
|
||||
class MemoryImageDataSource : public DataSource
|
||||
{
|
||||
public:
|
||||
//! \brief Default constructor.
|
||||
MemoryImageDataSource(StExecutableImage *image);
|
||||
|
||||
//! \brief Destructor.
|
||||
virtual ~MemoryImageDataSource();
|
||||
|
||||
//! \brief Returns the number of memory regions in the image.
|
||||
virtual unsigned getSegmentCount();
|
||||
|
||||
//! \brief Returns the data source segment at position \a index.
|
||||
virtual DataSource::Segment *getSegmentAt(unsigned index);
|
||||
|
||||
protected:
|
||||
/*!
|
||||
* \brief Segment corresponding to a text region of the executable image.
|
||||
*/
|
||||
class TextSegment : public DataSource::Segment
|
||||
{
|
||||
public:
|
||||
//! \brief Default constructor
|
||||
TextSegment(MemoryImageDataSource &source, StExecutableImage *image, unsigned index);
|
||||
|
||||
virtual unsigned getData(unsigned offset, unsigned maxBytes, uint8_t *buffer);
|
||||
virtual unsigned getLength();
|
||||
|
||||
virtual bool hasNaturalLocation() { return true; }
|
||||
virtual uint32_t getBaseAddress();
|
||||
|
||||
protected:
|
||||
StExecutableImage *m_image; //!< Coalesced image of the file.
|
||||
unsigned m_index; //!< Record index.
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Segment corresponding to a fill region of the executable image.
|
||||
*/
|
||||
class FillSegment : public DataSource::PatternSegment
|
||||
{
|
||||
public:
|
||||
FillSegment(MemoryImageDataSource &source, StExecutableImage *image, unsigned index);
|
||||
|
||||
virtual unsigned getLength();
|
||||
|
||||
virtual bool hasNaturalLocation() { return true; }
|
||||
virtual uint32_t getBaseAddress();
|
||||
|
||||
protected:
|
||||
StExecutableImage *m_image; //!< Coalesced image of the file.
|
||||
unsigned m_index; //!< Record index.
|
||||
};
|
||||
|
||||
protected:
|
||||
StExecutableImage *m_image; //!< The memory image that is the data source.
|
||||
|
||||
typedef std::vector<DataSource::Segment *> segment_array_t; //!< An array of segments.
|
||||
segment_array_t m_segments; //!< The array of Segment instances.
|
||||
};
|
||||
|
||||
}; // namespace elftosb
|
||||
|
||||
#endif // _DataSource_h_
|
||||
142
apps/elftosb/common/DataSourceImager.cpp
Normal file
142
apps/elftosb/common/DataSourceImager.cpp
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* File: DataSourceImager.cpp
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
|
||||
#include "DataSourceImager.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
using namespace elftosb;
|
||||
|
||||
DataSourceImager::DataSourceImager()
|
||||
: Blob()
|
||||
, m_fill(0)
|
||||
, m_baseAddress(0)
|
||||
, m_isBaseAddressSet(false)
|
||||
{
|
||||
}
|
||||
|
||||
void DataSourceImager::setBaseAddress(uint32_t address)
|
||||
{
|
||||
m_baseAddress = address;
|
||||
m_isBaseAddressSet = true;
|
||||
}
|
||||
|
||||
void DataSourceImager::setFillPattern(uint8_t pattern)
|
||||
{
|
||||
m_fill = pattern;
|
||||
}
|
||||
|
||||
void DataSourceImager::reset()
|
||||
{
|
||||
clear();
|
||||
|
||||
m_fill = 0;
|
||||
m_baseAddress = 0;
|
||||
m_isBaseAddressSet = false;
|
||||
}
|
||||
|
||||
//! \param dataSource Pointer to an instance of a concrete data source subclass.
|
||||
//!
|
||||
void DataSourceImager::addDataSource(DataSource *source)
|
||||
{
|
||||
unsigned segmentCount = source->getSegmentCount();
|
||||
unsigned index = 0;
|
||||
for (; index < segmentCount; ++index)
|
||||
{
|
||||
addDataSegment(source->getSegmentAt(index));
|
||||
}
|
||||
}
|
||||
|
||||
//! \param segment The segment to add. May be any type of data segment, including
|
||||
//! a pattern segment.
|
||||
void DataSourceImager::addDataSegment(DataSource::Segment *segment)
|
||||
{
|
||||
DataSource::PatternSegment *patternSegment = dynamic_cast<DataSource::PatternSegment *>(segment);
|
||||
|
||||
unsigned segmentLength = segment->getLength();
|
||||
bool segmentHasLocation = segment->hasNaturalLocation();
|
||||
uint32_t segmentAddress = segment->getBaseAddress();
|
||||
|
||||
uint8_t *toPtr = NULL;
|
||||
unsigned addressDelta;
|
||||
unsigned newLength;
|
||||
|
||||
// If a pattern segment's length is 0 then make it as big as the fill pattern.
|
||||
// This needs to be done before the buffer is adjusted.
|
||||
if (patternSegment && segmentLength == 0)
|
||||
{
|
||||
SizedIntegerValue &pattern = patternSegment->getPattern();
|
||||
segmentLength = pattern.getSize();
|
||||
}
|
||||
|
||||
if (segmentLength)
|
||||
{
|
||||
if (segmentHasLocation)
|
||||
{
|
||||
// Make sure a base address is set.
|
||||
if (!m_isBaseAddressSet)
|
||||
{
|
||||
m_baseAddress = segmentAddress;
|
||||
m_isBaseAddressSet = true;
|
||||
}
|
||||
|
||||
// The segment is located before our buffer's first address.
|
||||
// toPtr is not set in this if, but in the else branch of the next if.
|
||||
// Unless the segment completely overwrite the current data.
|
||||
if (segmentAddress < m_baseAddress)
|
||||
{
|
||||
addressDelta = m_baseAddress - segmentAddress;
|
||||
|
||||
uint8_t *newData = (uint8_t *)malloc(m_length + addressDelta);
|
||||
memcpy(&newData[addressDelta], m_data, m_length);
|
||||
free(m_data);
|
||||
|
||||
m_data = newData;
|
||||
m_length += addressDelta;
|
||||
m_baseAddress = segmentAddress;
|
||||
}
|
||||
|
||||
// This segment is located or extends outside of our buffer.
|
||||
if (segmentAddress + segmentLength > m_baseAddress + m_length)
|
||||
{
|
||||
newLength = segmentAddress + segmentLength - m_baseAddress;
|
||||
|
||||
m_data = (uint8_t *)realloc(m_data, newLength);
|
||||
|
||||
// Clear any bytes between the old data and the new segment.
|
||||
addressDelta = segmentAddress - (m_baseAddress + m_length);
|
||||
if (addressDelta)
|
||||
{
|
||||
memset(m_data + m_length, 0, addressDelta);
|
||||
}
|
||||
|
||||
toPtr = m_data + (segmentAddress - m_baseAddress);
|
||||
m_length = newLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
toPtr = m_data + (segmentAddress - m_baseAddress);
|
||||
}
|
||||
}
|
||||
// Segment has no natural location, so just append it to the end of our buffer.
|
||||
else
|
||||
{
|
||||
newLength = m_length + segmentLength;
|
||||
m_data = (uint8_t *)realloc(m_data, newLength);
|
||||
toPtr = m_data + m_length;
|
||||
m_length = newLength;
|
||||
}
|
||||
}
|
||||
|
||||
// A loop is used because getData() may fill in less than the requested
|
||||
// number of bytes per call.
|
||||
unsigned offset = 0;
|
||||
while (offset < segmentLength)
|
||||
{
|
||||
offset += segment->getData(offset, segmentLength - offset, toPtr + offset);
|
||||
}
|
||||
}
|
||||
53
apps/elftosb/common/DataSourceImager.h
Normal file
53
apps/elftosb/common/DataSourceImager.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* File: DataSourceImager.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
#if !defined(_DataSourceImager_h_)
|
||||
#define _DataSourceImager_h_
|
||||
|
||||
#include "Blob.h"
|
||||
#include "DataSource.h"
|
||||
|
||||
namespace elftosb
|
||||
{
|
||||
/*!
|
||||
* \brief Converts a DataSource into a single binary buffer.
|
||||
*/
|
||||
class DataSourceImager : public Blob
|
||||
{
|
||||
public:
|
||||
//! \brief Constructor.
|
||||
DataSourceImager();
|
||||
|
||||
//! \name Setup
|
||||
//@{
|
||||
void setBaseAddress(uint32_t address);
|
||||
void setFillPattern(uint8_t pattern);
|
||||
//@}
|
||||
|
||||
void reset();
|
||||
|
||||
//! \name Accessors
|
||||
//@{
|
||||
uint32_t getBaseAddress() { return m_baseAddress; }
|
||||
//@}
|
||||
|
||||
//! \name Operations
|
||||
//@{
|
||||
//! \brief Adds all of the segments of which \a dataSource is composed.
|
||||
void addDataSource(DataSource *source);
|
||||
|
||||
//! \brief Adds the data from one data segment.
|
||||
void addDataSegment(DataSource::Segment *segment);
|
||||
//@}
|
||||
|
||||
protected:
|
||||
uint8_t m_fill;
|
||||
uint32_t m_baseAddress;
|
||||
bool m_isBaseAddressSet;
|
||||
};
|
||||
};
|
||||
|
||||
#endif // _DataSourceImager_h_
|
||||
64
apps/elftosb/common/DataTarget.cpp
Normal file
64
apps/elftosb/common/DataTarget.cpp
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* File: DataTarget.cpp
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
|
||||
#include "DataTarget.h"
|
||||
#include "DataSource.h"
|
||||
#include "ElftosbErrors.h"
|
||||
#include <algorithm>
|
||||
|
||||
using namespace elftosb;
|
||||
|
||||
//! \exception elftosb::semantic_error Thrown if the source has multiple segments.
|
||||
DataTarget::AddressRange ConstantDataTarget::getRangeForSegment(DataSource &source, DataSource::Segment &segment)
|
||||
{
|
||||
// can't handle multi-segment data sources
|
||||
if (source.getSegmentCount() > 1)
|
||||
{
|
||||
throw semantic_error("constant targets only support single-segment sources");
|
||||
}
|
||||
|
||||
// always relocate the segment to our begin address
|
||||
AddressRange range;
|
||||
range.m_begin = m_begin;
|
||||
|
||||
if (isBounded())
|
||||
{
|
||||
// we have an end address. trim the result range to the segment size
|
||||
// or let the end address crop the segment.
|
||||
uint64_t sourceBasedEnd = static_cast<uint64_t>(m_begin) + static_cast<uint64_t>(segment.getLength());
|
||||
if (sourceBasedEnd > ULONG_MAX)
|
||||
{
|
||||
sourceBasedEnd = ULONG_MAX;
|
||||
}
|
||||
range.m_end = std::min<uint32_t>(m_end, static_cast<uint32_t>(sourceBasedEnd));
|
||||
}
|
||||
else
|
||||
{
|
||||
// we have no end address, so the segment size determines it.
|
||||
range.m_end = m_begin + segment.getLength();
|
||||
}
|
||||
|
||||
return range;
|
||||
}
|
||||
|
||||
//! If the \a segment has a natural location, the returned address range extends
|
||||
//! from the segment's base address to its base address plus its length.
|
||||
//!
|
||||
//! \exception elftosb::semantic_error This exception is thrown if the \a segment
|
||||
//! does not have a natural location associated with it.
|
||||
DataTarget::AddressRange NaturalDataTarget::getRangeForSegment(DataSource &source, DataSource::Segment &segment)
|
||||
{
|
||||
if (!segment.hasNaturalLocation())
|
||||
{
|
||||
throw semantic_error("source has no natural location");
|
||||
}
|
||||
|
||||
AddressRange range;
|
||||
range.m_begin = segment.getBaseAddress();
|
||||
range.m_end = segment.getBaseAddress() + segment.getLength();
|
||||
return range;
|
||||
}
|
||||
132
apps/elftosb/common/DataTarget.h
Normal file
132
apps/elftosb/common/DataTarget.h
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* File: DataTarget.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
#if !defined(_DataTarget_h_)
|
||||
#define _DataTarget_h_
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "DataSource.h"
|
||||
|
||||
namespace elftosb
|
||||
{
|
||||
// Forward declaration
|
||||
class DataSource;
|
||||
|
||||
/*!
|
||||
* \brief Abstract base class for the target address or range of data.
|
||||
*
|
||||
* Targets at the most basic level have a single address, and potentially
|
||||
* an address range. Unbounded targets have a beginning address but no
|
||||
* specific end address, while bounded targets do have an end address.
|
||||
*
|
||||
* Users of a data target can access the begin and end addresses directly.
|
||||
* However, the most powerful way to use a target is with the
|
||||
* getRangeForSegment() method. This method returns the target address range
|
||||
* for a segment of a data source. The value of the resulting range can be
|
||||
* completely dependent upon the segment's properties, those of its data
|
||||
* source, and the type of data target.
|
||||
*
|
||||
* \see elftosb::DataSource
|
||||
*/
|
||||
class DataTarget
|
||||
{
|
||||
public:
|
||||
//! \brief Simple structure that describes an addressed region of memory.
|
||||
//! \todo Decide if the end address is inclusive or not.
|
||||
struct AddressRange
|
||||
{
|
||||
uint32_t m_begin;
|
||||
uint32_t m_end;
|
||||
};
|
||||
|
||||
public:
|
||||
//! \brief Default constructor.
|
||||
DataTarget()
|
||||
: m_source(0)
|
||||
{
|
||||
}
|
||||
|
||||
//! \brief Destructor.
|
||||
virtual ~DataTarget() {}
|
||||
//! \brief Whether the target is just a single address or has an end to it.
|
||||
virtual bool isBounded() { return false; }
|
||||
virtual uint32_t getBeginAddress() { return 0; }
|
||||
virtual uint32_t getEndAddress() { return 0; }
|
||||
//! \brief Return the address range for a segment of a data source.
|
||||
virtual DataTarget::AddressRange getRangeForSegment(DataSource &source, DataSource::Segment &segment) = 0;
|
||||
|
||||
inline void setSource(DataSource *source) { m_source = source; }
|
||||
inline DataSource *getSource() const { return m_source; }
|
||||
protected:
|
||||
DataSource *m_source; //!< Corresponding data source for this target.
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Target with a constant values for the addresses.
|
||||
*
|
||||
* This target type supports can be both bounded and unbounded. It always has
|
||||
* at least one address, the beginning address. The end address is optional,
|
||||
* and if not provided makes the target unbounded.
|
||||
*/
|
||||
class ConstantDataTarget : public DataTarget
|
||||
{
|
||||
public:
|
||||
//! \brief Constructor taking only a begin address.
|
||||
ConstantDataTarget(uint32_t start)
|
||||
: DataTarget()
|
||||
, m_begin(start)
|
||||
, m_end(0)
|
||||
, m_hasEnd(false)
|
||||
{
|
||||
}
|
||||
|
||||
//! \brief Constructor taking both begin and end addresses.
|
||||
ConstantDataTarget(uint32_t start, uint32_t end)
|
||||
: DataTarget()
|
||||
, m_begin(start)
|
||||
, m_end(end)
|
||||
, m_hasEnd(true)
|
||||
{
|
||||
}
|
||||
|
||||
//! \brief The target is bounded if an end address was specified.
|
||||
virtual bool isBounded() { return m_hasEnd; }
|
||||
virtual uint32_t getBeginAddress() { return m_begin; }
|
||||
virtual uint32_t getEndAddress() { return m_end; }
|
||||
//! \brief Return the address range for a segment of a data source.
|
||||
virtual DataTarget::AddressRange getRangeForSegment(DataSource &source, DataSource::Segment &segment);
|
||||
|
||||
protected:
|
||||
uint32_t m_begin; //!< Start address.
|
||||
uint32_t m_end; //!< End address.
|
||||
bool m_hasEnd; //!< Was an end address specified?
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Target address that is the "natural" location of whatever the source data is.
|
||||
*
|
||||
* The data source used with the target must have a natural location. If
|
||||
* getRangeForSegment() is called with a segment that does not have a natural
|
||||
* location, a semantic_error will be thrown.
|
||||
*/
|
||||
class NaturalDataTarget : public DataTarget
|
||||
{
|
||||
public:
|
||||
//! \brief Default constructor.
|
||||
NaturalDataTarget()
|
||||
: DataTarget()
|
||||
{
|
||||
}
|
||||
|
||||
//! \brief Natural data targets are bounded by their source's segment lengths.
|
||||
virtual bool isBounded() { return true; }
|
||||
//! \brief Return the address range for a segment of a data source.
|
||||
virtual DataTarget::AddressRange getRangeForSegment(DataSource &source, DataSource::Segment &segment);
|
||||
};
|
||||
|
||||
}; // namespace elftosb
|
||||
|
||||
#endif // _DataTarget_h_
|
||||
349
apps/elftosb/common/ELF.h
Normal file
349
apps/elftosb/common/ELF.h
Normal file
@@ -0,0 +1,349 @@
|
||||
/*
|
||||
* File: ELF.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
#if !defined(_ELF_h_)
|
||||
#define _ELF_h_
|
||||
|
||||
//! \name ELF types
|
||||
//! Types used in ELF file structures.
|
||||
//@{
|
||||
typedef uint32_t Elf32_Addr;
|
||||
typedef uint16_t Elf32_Half;
|
||||
typedef /*off_t*/ uint32_t Elf32_Off;
|
||||
typedef int32_t Elf32_Sword;
|
||||
typedef uint32_t Elf32_Word;
|
||||
//@}
|
||||
|
||||
// All ELF structures are byte aligned. Any alignment padding is explicit.
|
||||
#pragma pack(1)
|
||||
|
||||
//! \name File header
|
||||
//@{
|
||||
|
||||
/*!
|
||||
* Constants for the various fields of Elf32_Ehdr.e_ident.
|
||||
*/
|
||||
enum
|
||||
{
|
||||
EI_MAG0 = 0,
|
||||
EI_MAG1,
|
||||
EI_MAG2,
|
||||
EI_MAG3,
|
||||
EI_CLASS,
|
||||
EI_DATA,
|
||||
EI_VERSION,
|
||||
EI_PAD,
|
||||
EI_NIDENT = 16,
|
||||
|
||||
// Magic number.
|
||||
ELFMAG0 = 0x7f,
|
||||
ELFMAG1 = 'E',
|
||||
ELFMAG2 = 'L',
|
||||
ELFMAG3 = 'F',
|
||||
|
||||
// EI_CLASS
|
||||
ELFCLASSNONE = 0,
|
||||
ELFCLASS32 = 1,
|
||||
ELFCLASS64 = 2,
|
||||
|
||||
// EI_DATA
|
||||
ELFDATANONE = 0,
|
||||
ELFDATA2LSB = 1,
|
||||
ELFDATA2MSB = 2
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief ELF file header.
|
||||
*/
|
||||
struct Elf32_Ehdr
|
||||
{
|
||||
unsigned char e_ident[EI_NIDENT]; //!< Magic number identifying the file format.
|
||||
Elf32_Half e_type; //!< Identifies the object file format.
|
||||
Elf32_Half e_machine; //!< Specified the architecture for the object file.
|
||||
Elf32_Word e_version; //!< Object file version.
|
||||
Elf32_Addr e_entry; //!< Virtual address of the entry point, or 0.
|
||||
Elf32_Off e_phoff; //!< Program header table offset in bytes, or 0 if no program header table.
|
||||
Elf32_Off e_shoff; //!< Section header table offset in bytes, or 0 if no section header table.
|
||||
Elf32_Word e_flags; //!< Processor-specific flags associated with the file.
|
||||
Elf32_Half e_ehsize; //!< The ELF header's size in bytes.
|
||||
Elf32_Half e_phentsize; //!< Size in bytes of one entry in the program header table.
|
||||
Elf32_Half e_phnum; //!< Number of entries in the program header table.
|
||||
Elf32_Half e_shentsize; //!< Size in bytes of an entry in the section header table.
|
||||
Elf32_Half e_shnum; //!< Number of entries in the section header table.
|
||||
Elf32_Half e_shstrndx; //!< Section header table index of the section name string table.
|
||||
};
|
||||
|
||||
/*!
|
||||
* Constants for #Elf32_Ehdr.e_type.
|
||||
*/
|
||||
enum
|
||||
{
|
||||
ET_NONE, //!< No file type.
|
||||
ET_REL, //!< Relocatable file.
|
||||
ET_EXEC, //!< Executable file.
|
||||
ET_DYN, //!< Shared object file.
|
||||
ET_CORE, //!< Core file.
|
||||
ET_LOPROC, //!< Low bound of processor-specific file types.
|
||||
ET_HIPROC //!< High bound of processor-specific file types.
|
||||
};
|
||||
|
||||
/*!
|
||||
* ARM-specific #Elf32_Ehdr.e_flags
|
||||
*/
|
||||
enum
|
||||
{
|
||||
EF_ARM_HASENTRY = 0x02, //!< #Elf32_Ehdr.e_entry contains a program-loader entry point.
|
||||
EF_ARM_SYMSARESORTED = 0x04, //!< Each subsection of the symbol table is sorted by symbol value.
|
||||
EF_ARM_DYNSYMSUSESEGIDX = 0x08, //!< Symbols in dynamic symbol tables that are defined in sections included in
|
||||
//!program segment n have #Elf32_Sym.st_shndx = n + 1.
|
||||
EF_ARM_MAPSYMSFIRST = 0x10, //!< Mapping symbols precede other local symbols in the symbol table.
|
||||
EF_ARM_EABIMASK = 0xff000000, //!< This masks an 8-bit version number, the version of the ARM EABI to which this ELF
|
||||
//!file conforms. The current EABI version is #ARM_EABI_VERSION.
|
||||
|
||||
ARM_EABI_VERSION = 0x02000000 //!< Current ARM EABI version.
|
||||
};
|
||||
|
||||
//@}
|
||||
|
||||
//! \name Sections
|
||||
//@{
|
||||
|
||||
/*!
|
||||
* \brief ELF section header.
|
||||
*
|
||||
* An object file's section header table lets one locate all the file's
|
||||
* sections. The section header table is an array of #Elf32_Shdr structures.
|
||||
* A section header table index is a subscript into this array. The ELF
|
||||
* header's #Elf32_Ehdr::e_shoff member gives the byte offset from the beginning of
|
||||
* the file to the section header table; #Elf32_Ehdr::e_shnum tells how many entries
|
||||
* the section header table contains; #Elf32_Ehdr::e_shentsize gives the size in bytes
|
||||
* of each entry.
|
||||
*
|
||||
* Some section header table indexes are reserved. An object file will not
|
||||
* have sections for these special indexes:
|
||||
* - #SHN_UNDEF
|
||||
* - #SHN_LORESERVE
|
||||
* - #SHN_LOPROC
|
||||
* - #SHN_HIPROC
|
||||
* - #SHN_ABS
|
||||
* - #SHN_COMMON
|
||||
* - #SHN_HIRESERVE
|
||||
*/
|
||||
struct Elf32_Shdr
|
||||
{
|
||||
Elf32_Word sh_name; //!< The section's name. Index into the section header string table section.
|
||||
Elf32_Word sh_type; //!< Section type, describing the contents and semantics.
|
||||
Elf32_Word sh_flags; //!< Section flags describing various attributes.
|
||||
Elf32_Addr sh_addr; //!< The address at which the section will appear in the memory image, or 0.
|
||||
Elf32_Off sh_offset; //!< Offset from beginning of the file to the first byte in the section.
|
||||
Elf32_Word sh_size; //!< The section's size in bytes.
|
||||
Elf32_Word sh_link; //!< Section header table link index. Interpretation depends on section type.
|
||||
Elf32_Word sh_info; //!< Extra information about the section. Depends on section type.
|
||||
Elf32_Word sh_addralign; //!< Address alignment constraint. Values are 0 and positive powers of 2.
|
||||
Elf32_Word sh_entsize; //!< Size in bytes of section entries, or 0 if the section does not have fixed-size entries.
|
||||
};
|
||||
|
||||
/*!
|
||||
* Special section indexes.
|
||||
*/
|
||||
enum
|
||||
{
|
||||
SHN_UNDEF = 0,
|
||||
SHN_LORESERVE = 0xff00,
|
||||
SHN_LOPROC = 0xff00,
|
||||
SHN_HIPROC = 0xff1f,
|
||||
SHN_ABS = 0xfff1, //!< The symbol has an absolute value that will not change because of relocation.
|
||||
SHN_COMMON = 0xfff2, //!< The symbol labels a common block that has not yet been allocated.
|
||||
SHN_HIRESERVE = 0xffff
|
||||
};
|
||||
|
||||
/*!
|
||||
* Section type constants.
|
||||
*/
|
||||
enum
|
||||
{
|
||||
SHT_NULL = 0,
|
||||
SHT_PROGBITS = 1,
|
||||
SHT_SYMTAB = 2,
|
||||
SHT_STRTAB = 3,
|
||||
SHT_RELA = 4,
|
||||
SHT_HASH = 5,
|
||||
SHT_DYNAMIC = 6,
|
||||
SHT_NOTE = 7,
|
||||
SHT_NOBITS = 8,
|
||||
SHT_REL = 9,
|
||||
SHT_SHLIB = 10,
|
||||
SHT_DYNSYM = 11
|
||||
};
|
||||
|
||||
/*!
|
||||
* Section flag constants.
|
||||
*/
|
||||
enum
|
||||
{
|
||||
SHF_WRITE = 0x1, //!< Section is writable.
|
||||
SHF_ALLOC = 0x2, //!< Allocate section.
|
||||
SHF_EXECINSTR = 0x4 //!< Section contains executable instructions.
|
||||
};
|
||||
|
||||
/*!
|
||||
* ARM-specific section flag constants
|
||||
*/
|
||||
enum
|
||||
{
|
||||
SHF_ENTRYSECT = 0x10000000, //!< The section contains an entry point.
|
||||
SHF_COMDEF = 0x80000000 //!< The section may be multiply defined in the input to a link step.
|
||||
};
|
||||
|
||||
#define BSS_SECTION_NAME ".bss"
|
||||
#define DATA_SECTION_NAME ".data"
|
||||
#define TEXT_SECTION_NAME ".text"
|
||||
#define SHSTRTAB_SECTION_NAME ".shstrtab"
|
||||
#define STRTAB_SECTION_NAME ".strtab"
|
||||
#define SYMTAB_SECTION_NAME ".symtab"
|
||||
|
||||
//@}
|
||||
|
||||
//! \name Segments
|
||||
//@{
|
||||
|
||||
/*!
|
||||
* \brief ELF program header.
|
||||
*
|
||||
* An executable or shared object file's program header table is an array of
|
||||
* structures, each describing a segment or other information the system needs
|
||||
* to prepare the program for execution. An object file segment contains one
|
||||
* or more sections. Program headers are meaningful only for executable and
|
||||
* shared object files. A file specifies its own program header size with the
|
||||
* ELF header's #Elf32_Ehdr::e_phentsize and #Elf32_Ehdr::e_phnum members.
|
||||
*/
|
||||
struct Elf32_Phdr
|
||||
{
|
||||
Elf32_Word p_type; //!< What type of segment this header describes.
|
||||
Elf32_Off p_offset; //!< Offset in bytes from start of file to the first byte of the segment.
|
||||
Elf32_Addr p_vaddr; //!< Virtual address at which the segment will reside in memory.
|
||||
Elf32_Addr p_paddr; //!< Physical address, for systems where this is relevant.
|
||||
Elf32_Word p_filesz; //!< Number of bytes of file data the segment consumes. May be zero.
|
||||
Elf32_Word p_memsz; //!< Size in bytes of the segment in memory. May be zero.
|
||||
Elf32_Word p_flags; //!< Flags relevant to the segment.
|
||||
Elf32_Word p_align; //!< Alignment constraint for segment addresses. Possible values are 0 and positive powers of 2.
|
||||
};
|
||||
|
||||
/*!
|
||||
* Segment type constants.
|
||||
*/
|
||||
enum
|
||||
{
|
||||
PT_NULL = 0,
|
||||
PT_LOAD = 1,
|
||||
PT_DYNAMIC = 2,
|
||||
PT_INTERP = 3,
|
||||
PT_NOTE = 4,
|
||||
PT_SHLIB = 5,
|
||||
PT_PHDR = 6
|
||||
};
|
||||
|
||||
/*!
|
||||
* Program header flag constants.
|
||||
*/
|
||||
enum
|
||||
{
|
||||
PF_X = 0x1, //!< Segment is executable.
|
||||
PF_W = 0x2, //!< Segment is writable.
|
||||
PF_R = 0x4 //!< Segment is readable.
|
||||
};
|
||||
|
||||
//@}
|
||||
|
||||
//! \name Symbol table
|
||||
//@{
|
||||
|
||||
enum
|
||||
{
|
||||
STN_UNDEF = 0 //!< Undefined symbol index.
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief ELF symbol table entry.
|
||||
*
|
||||
* An object file's symbol table holds information needed to locate and
|
||||
* relocate a program's symbolic definitions and references. A symbol
|
||||
* table index is a subscript into this array. Index 0 both designates
|
||||
* the first entry in the table and serves as the undefined symbol index.
|
||||
*/
|
||||
struct Elf32_Sym
|
||||
{
|
||||
Elf32_Word st_name; //!< Index into file's string table.
|
||||
Elf32_Addr st_value; //!< Value associated with the symbol. Depends on context.
|
||||
Elf32_Word st_size; //!< Size associated with symbol. 0 if the symbol has no size or an unknown size.
|
||||
unsigned char st_info; //!< Specified the symbol's type and binding attributes.
|
||||
unsigned char st_other; //!< Currently 0 (reserved).
|
||||
Elf32_Half st_shndx; //!< Section header table index for this symbol.
|
||||
};
|
||||
|
||||
//! \name st_info macros
|
||||
//! Macros for manipulating the st_info field of Elf32_Sym struct.
|
||||
//@{
|
||||
#define ELF32_ST_BIND(i) ((i) >> 4) //!< Get binding attributes.
|
||||
#define ELF32_ST_TYPE(i) ((i)&0x0f) //!< Get symbol type.
|
||||
#define ELF32_ST_INFO(b, t) \
|
||||
(((b) << 4) + ((t)&0x0f)) //!< Construct st_info value from binding attributes and symbol type.
|
||||
//@}
|
||||
|
||||
/*!
|
||||
* \brief Symbol binding attributes.
|
||||
*
|
||||
* These constants are mask values.
|
||||
*/
|
||||
enum
|
||||
{
|
||||
STB_LOCAL = 0, //!< Local symbol not visible outside the object file.
|
||||
STB_GLOBAL = 1, //!< Symbol is visible to all object files being linked together.
|
||||
STB_WEAK = 2, //!< Like global symbols, but with lower precedence.
|
||||
|
||||
// Processor-specific semantics.
|
||||
STB_LOPROC = 13,
|
||||
STB_HIPROC = 15
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Symbol types.
|
||||
*/
|
||||
enum
|
||||
{
|
||||
STT_NOTYPE = 0, //!< The symbol's type is not specified.
|
||||
STT_OBJECT = 1, //!< The symbol is associated with a data object, such as a variable or array.
|
||||
STT_FUNC = 2, //!< The symbol is associated with a function or other executable code.
|
||||
STT_SECTION = 3, //!< The synmbol is associated with a section. Primarily used for relocation.
|
||||
STT_FILE = 4, //!< A file symbol has STB_LOCAL binding, its section index is SHN_ABS, and it precedes the other
|
||||
//!STB_LOCAL symbols for the file, if it is present.
|
||||
|
||||
STT_LOPROC = 13, //!< Low bound of processor-specific symbol types.
|
||||
STT_HIPROC = 15 //!< High bound of processor-specific symbol types.
|
||||
};
|
||||
|
||||
/*!
|
||||
* GHS-specific constants
|
||||
*/
|
||||
enum
|
||||
{
|
||||
STO_THUMB = 1 //!< This flag is set on #Elf32_Sym.st_other if the symbol is Thumb mode code.
|
||||
};
|
||||
|
||||
#define ARM_SEQUENCE_MAPSYM "$a"
|
||||
#define DATA_SEQUENCE_MAPSYM "$d"
|
||||
#define THUMB_SEQUENCE_MAPSYM "$t"
|
||||
|
||||
#define THUMB_BL_TAGSYM "$b"
|
||||
#define FN_PTR_CONST_TAGSYM "$f"
|
||||
#define INDIRECT_FN_CALL_TAGSYM "$p"
|
||||
#define MAPPING_SYMBOL_COUNT_TAGSYM "$m"
|
||||
|
||||
//@}
|
||||
|
||||
#pragma pack()
|
||||
|
||||
#endif // _ELF_h_
|
||||
546
apps/elftosb/common/ELFSourceFile.cpp
Normal file
546
apps/elftosb/common/ELFSourceFile.cpp
Normal file
File diff suppressed because it is too large
Load Diff
225
apps/elftosb/common/ELFSourceFile.h
Normal file
225
apps/elftosb/common/ELFSourceFile.h
Normal file
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
* File: ELFSourceFile.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
#if !defined(_ELFSourceFile_h_)
|
||||
#define _ELFSourceFile_h_
|
||||
|
||||
#include "SourceFile.h"
|
||||
#include "StELFFile.h"
|
||||
#include "smart_ptr.h"
|
||||
#include "DataSource.h"
|
||||
#include "DataTarget.h"
|
||||
#include "ELF.h"
|
||||
|
||||
namespace elftosb
|
||||
{
|
||||
//! Set of supported compiler toolsets.
|
||||
enum elf_toolset_t
|
||||
{
|
||||
kUnknownToolset, //!< Unknown.
|
||||
kGHSToolset, //!< Green Hills Software MULTI
|
||||
kGCCToolset, //!< GNU GCC
|
||||
kADSToolset, //!< ARM UK RealView
|
||||
kIARToolset, //!< IAR
|
||||
kKDSToolset, //!< KDS
|
||||
kKeilToolset //!< Keil
|
||||
};
|
||||
|
||||
//! Options for handling the .secinfo section in GHS-produced ELF files.
|
||||
enum secinfo_clear_t
|
||||
{
|
||||
// Default value for the .secinfo action.
|
||||
kSecinfoDefault,
|
||||
|
||||
//! Ignore the .secinfo section if present. The standard ELF loading
|
||||
//! rules are followed.
|
||||
kSecinfoIgnore,
|
||||
|
||||
//! The boot ROM clears only those SHT_NOBITS sections present in .secinfo.
|
||||
kSecinfoROMClear,
|
||||
|
||||
//! The C startup is responsible for clearing sections. No fill commands
|
||||
//! are generated for any SHT_NOBITS sections.
|
||||
kSecinfoCStartupClear
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Executable and Loading Format (ELF) source file.
|
||||
*/
|
||||
class ELFSourceFile : public SourceFile
|
||||
{
|
||||
public:
|
||||
//! \brief Default constructor.
|
||||
ELFSourceFile(const std::string &path);
|
||||
|
||||
//! \brief Destructor.
|
||||
virtual ~ELFSourceFile();
|
||||
|
||||
//! \brief Identifies whether the stream contains an ELF file.
|
||||
static bool isELFFile(std::istream &stream);
|
||||
|
||||
//! \name Opening and closing
|
||||
//@{
|
||||
//! \brief Opens the file.
|
||||
virtual void open();
|
||||
|
||||
//! \brief Closes the file.
|
||||
virtual void close();
|
||||
//@}
|
||||
|
||||
//! \name Format capabilities
|
||||
//@{
|
||||
virtual bool supportsNamedSections() const { return true; }
|
||||
virtual bool supportsNamedSymbols() const { return true; }
|
||||
//@}
|
||||
|
||||
//! \name Data source
|
||||
//@{
|
||||
//! \brief Creates a data source from the entire file.
|
||||
virtual DataSource *createDataSource();
|
||||
|
||||
//! \brief Creates a data source from one or more sections of the file.
|
||||
virtual DataSource *createDataSource(StringMatcher &matcher);
|
||||
//@}
|
||||
|
||||
//! \name Entry point
|
||||
//@{
|
||||
//! \brief Returns true if an entry point was set in the file.
|
||||
virtual bool hasEntryPoint();
|
||||
|
||||
//! \brief Returns the entry point address.
|
||||
virtual uint32_t getEntryPointAddress();
|
||||
//@}
|
||||
|
||||
//! \name Data target
|
||||
//@{
|
||||
virtual DataTarget *createDataTargetForSection(const std::string §ion);
|
||||
virtual DataTarget *createDataTargetForSymbol(const std::string &symbol);
|
||||
//@}
|
||||
|
||||
//! \name Symbols
|
||||
//@{
|
||||
//! \brief Returns whether a symbol exists in the source file.
|
||||
virtual bool hasSymbol(const std::string &name);
|
||||
|
||||
//! \brief Returns the value of a symbol.
|
||||
virtual uint32_t getSymbolValue(const std::string &name);
|
||||
|
||||
//! \brief Returns the size of a symbol.
|
||||
virtual unsigned getSymbolSize(const std::string &name);
|
||||
//@}
|
||||
|
||||
//! \name Direct ELF format access
|
||||
//@{
|
||||
//! \brief Returns the underlying StELFFile object.
|
||||
StELFFile *getELFFile() { return m_file; }
|
||||
//! \brief Gets information about a symbol in the ELF file.
|
||||
bool lookupSymbol(const std::string &name, Elf32_Sym &info);
|
||||
//@}
|
||||
|
||||
protected:
|
||||
smart_ptr<StELFFile> m_file; //!< Parser for the ELF file.
|
||||
elf_toolset_t m_toolset; //!< Toolset that produced the ELF file.
|
||||
secinfo_clear_t m_secinfoOption; //!< How to deal with the .secinfo section. Ignored if the toolset is not GHS.
|
||||
|
||||
protected:
|
||||
//! \brief Parses the toolset option value.
|
||||
elf_toolset_t readToolsetOption();
|
||||
|
||||
//! \brief Reads the secinfoClear option.
|
||||
secinfo_clear_t readSecinfoClearOption();
|
||||
|
||||
protected:
|
||||
/*!
|
||||
* \brief A data source with ELF file sections as the contents.
|
||||
*
|
||||
* Each segment of this data source corresponds directly with a named section
|
||||
* of the ELF file it represents. When the data source is created, it contains
|
||||
* no segments. Segments are created with the addSection() method, which takes
|
||||
* the index of an ELF section and creates a corresponding segment.
|
||||
*
|
||||
* Two segment subclasses are used with this data source. The first, ProgBitsSegment,
|
||||
* is used to represent sections whose type is #SHT_PROGBITS. These sections have
|
||||
* binary data stored in the ELF file. The second segment type is NoBitsSegment.
|
||||
* It is used to represent sections whose type is #SHT_NOBITS. These sections have
|
||||
* no data, but simply allocate a region of memory to be filled with zeroes.
|
||||
* As such, the NoBitsSegment class is a subclass of DataSource::PatternSegment.
|
||||
*/
|
||||
class ELFDataSource : public DataSource
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* \brief Represents one named #SHT_PROGBITS section within the ELF file.
|
||||
*/
|
||||
class ProgBitsSegment : public DataSource::Segment
|
||||
{
|
||||
public:
|
||||
ProgBitsSegment(ELFDataSource &source, StELFFile *elf, unsigned index);
|
||||
|
||||
virtual unsigned getData(unsigned offset, unsigned maxBytes, uint8_t *buffer);
|
||||
virtual unsigned getLength();
|
||||
|
||||
virtual bool hasNaturalLocation() { return true; }
|
||||
virtual uint32_t getBaseAddress();
|
||||
|
||||
protected:
|
||||
StELFFile *m_elf; //!< The format parser instance for this ELF file.
|
||||
unsigned m_sectionIndex; //!< The index of the section this segment represents.
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Represents one named #SHT_NOBITS section within the ELF file.
|
||||
*
|
||||
* This segment class is a subclass of DataSource::PatternSegment since it
|
||||
* represents a region of memory to be filled with zeroes.
|
||||
*/
|
||||
class NoBitsSegment : public DataSource::PatternSegment
|
||||
{
|
||||
public:
|
||||
NoBitsSegment(ELFDataSource &source, StELFFile *elf, unsigned index);
|
||||
|
||||
virtual unsigned getLength();
|
||||
|
||||
virtual bool hasNaturalLocation() { return true; }
|
||||
virtual uint32_t getBaseAddress();
|
||||
|
||||
protected:
|
||||
StELFFile *m_elf; //!< The format parser instance for this ELF file.
|
||||
unsigned m_sectionIndex; //!< The index of the section this segment represents.
|
||||
};
|
||||
|
||||
public:
|
||||
//! \brief Default constructor.
|
||||
ELFDataSource(StELFFile *elf)
|
||||
: DataSource()
|
||||
, m_elf(elf)
|
||||
{
|
||||
}
|
||||
|
||||
//! \brief Destructor.
|
||||
virtual ~ELFDataSource();
|
||||
|
||||
//! Set the option to control .secinfo usage.
|
||||
inline void setSecinfoOption(secinfo_clear_t option) { m_secinfoOption = option; }
|
||||
//! \brief Adds the ELF section at position \a sectionIndex to the data source.
|
||||
void addSection(unsigned sectionIndex);
|
||||
|
||||
//! \brief Returns the number of segments in the source.
|
||||
virtual unsigned getSegmentCount() { return (unsigned)m_segments.size(); }
|
||||
//! \brief Returns the segment at position \a index.
|
||||
virtual DataSource::Segment *getSegmentAt(unsigned index) { return m_segments[index]; }
|
||||
protected:
|
||||
StELFFile *m_elf; //!< The ELF file parser.
|
||||
secinfo_clear_t m_secinfoOption; //!< How to deal with the .secinfo section. Ignored if the toolset is not GHS.
|
||||
|
||||
typedef std::vector<DataSource::Segment *> segment_vector_t; //!< A list of segment instances.
|
||||
segment_vector_t m_segments; //!< The segments of this data source.
|
||||
};
|
||||
};
|
||||
|
||||
}; // namespace elftosb
|
||||
|
||||
#endif // _ELFSourceFile_h_
|
||||
1610
apps/elftosb/common/EncoreBootImage.cpp
Normal file
1610
apps/elftosb/common/EncoreBootImage.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1271
apps/elftosb/common/EncoreBootImage.h
Normal file
1271
apps/elftosb/common/EncoreBootImage.h
Normal file
File diff suppressed because it is too large
Load Diff
371
apps/elftosb/common/EncoreBootImageReader.cpp
Normal file
371
apps/elftosb/common/EncoreBootImageReader.cpp
Normal file
@@ -0,0 +1,371 @@
|
||||
/*
|
||||
* File: EncoreBootImageReader.cpp
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
|
||||
#include "EncoreBootImageReader.h"
|
||||
#include "SHA1.h"
|
||||
#include "rijndael.h"
|
||||
#include "RijndaelCBCMAC.h"
|
||||
#include <assert.h>
|
||||
#include "EndianUtilities.h"
|
||||
#include "Logging.h"
|
||||
|
||||
using namespace elftosb;
|
||||
|
||||
//! \post Stream head points to just after the image header.
|
||||
//! \exception read_error Thrown if the image header is invalid.
|
||||
void EncoreBootImageReader::readImageHeader()
|
||||
{
|
||||
// seek to beginning of the stream/file and read the plaintext header
|
||||
m_stream.seekg(0, std::ios_base::beg);
|
||||
if (m_stream.read((char *)&m_header, sizeof(m_header)).bad())
|
||||
{
|
||||
throw read_error("failed to read image header");
|
||||
}
|
||||
|
||||
m_header.m_flags = ENDIAN_LITTLE_TO_HOST_U16(m_header.m_flags);
|
||||
m_header.m_imageBlocks = ENDIAN_LITTLE_TO_HOST_U32(m_header.m_imageBlocks);
|
||||
m_header.m_firstBootTagBlock = ENDIAN_LITTLE_TO_HOST_U32(m_header.m_firstBootTagBlock);
|
||||
m_header.m_firstBootableSectionID = ENDIAN_LITTLE_TO_HOST_U32(m_header.m_firstBootableSectionID);
|
||||
m_header.m_keyCount = ENDIAN_LITTLE_TO_HOST_U16(m_header.m_keyCount);
|
||||
m_header.m_keyDictionaryBlock = ENDIAN_LITTLE_TO_HOST_U16(m_header.m_keyDictionaryBlock);
|
||||
m_header.m_headerBlocks = ENDIAN_LITTLE_TO_HOST_U16(m_header.m_headerBlocks);
|
||||
m_header.m_sectionCount = ENDIAN_LITTLE_TO_HOST_U16(m_header.m_sectionCount);
|
||||
m_header.m_sectionHeaderSize = ENDIAN_LITTLE_TO_HOST_U16(m_header.m_sectionHeaderSize);
|
||||
m_header.m_timestamp = ENDIAN_LITTLE_TO_HOST_U64(m_header.m_timestamp);
|
||||
|
||||
// m_header.m_componentVersion.m_major = ENDIAN_BIG_TO_HOST_U16(m_header.m_componentVersion.m_major);
|
||||
// m_header.m_componentVersion.m_minor = ENDIAN_BIG_TO_HOST_U16(m_header.m_componentVersion.m_minor);
|
||||
// m_header.m_componentVersion.m_revision = ENDIAN_BIG_TO_HOST_U16(m_header.m_componentVersion.m_revision);
|
||||
|
||||
// m_header.m_productVersion.m_major = ENDIAN_BIG_TO_HOST_U16(m_header.m_productVersion.m_major);
|
||||
// m_header.m_productVersion.m_minor = ENDIAN_BIG_TO_HOST_U16(m_header.m_productVersion.m_minor);
|
||||
// m_header.m_productVersion.m_revision = ENDIAN_BIG_TO_HOST_U16(m_header.m_productVersion.m_revision);
|
||||
|
||||
// check header signature 1
|
||||
if (m_header.m_signature[0] != 'S' || m_header.m_signature[1] != 'T' || m_header.m_signature[2] != 'M' ||
|
||||
m_header.m_signature[3] != 'P')
|
||||
{
|
||||
throw read_error("invalid signature 1");
|
||||
}
|
||||
|
||||
// check header signature 2 for version 1.1 and greater
|
||||
if ((m_header.m_majorVersion > 1 || (m_header.m_majorVersion == 1 && m_header.m_minorVersion >= 2)) &&
|
||||
(m_header.m_signature2[0] != 's' || m_header.m_signature2[1] != 'g' || m_header.m_signature2[2] != 't' ||
|
||||
m_header.m_signature2[3] != 'l'))
|
||||
{
|
||||
// throw read_error("invalid signature 2");
|
||||
Log::log(Logger::WARNING, "warning: invalid signature 2\n");
|
||||
}
|
||||
}
|
||||
|
||||
//! \pre The image header must have already been read with a call to readImageHeader().
|
||||
//!
|
||||
void EncoreBootImageReader::computeHeaderDigest(sha1_digest_t &digest)
|
||||
{
|
||||
CSHA1 hash;
|
||||
hash.Reset();
|
||||
hash.Update((uint8_t *)&m_header.m_signature, sizeof(m_header) - sizeof(sha1_digest_t));
|
||||
hash.Final();
|
||||
hash.GetHash(digest);
|
||||
}
|
||||
|
||||
//! \pre The image header must have already been read.
|
||||
//! \pre The DEK must have been found already.
|
||||
//! \post The stream head is at the end of the digest.
|
||||
void EncoreBootImageReader::readImageDigest()
|
||||
{
|
||||
unsigned digestPosition = sizeOfCipherBlocks(m_header.m_imageBlocks - 2);
|
||||
m_stream.seekg(digestPosition, std::ios_base::beg);
|
||||
|
||||
// read the two cipher blocks containing the digest, including padding
|
||||
cipher_block_t digestBlocks[2];
|
||||
if (m_stream.read((char *)&digestBlocks, sizeof(digestBlocks)).bad())
|
||||
{
|
||||
throw read_error("failed to read image digest");
|
||||
}
|
||||
|
||||
// decrypt the digest
|
||||
if (isEncrypted())
|
||||
{
|
||||
Rijndael cipher;
|
||||
cipher.init(Rijndael::CBC, Rijndael::Decrypt, m_dek, Rijndael::Key16Bytes, m_header.m_iv);
|
||||
cipher.blockDecrypt((uint8_t *)&digestBlocks, sizeof(digestBlocks) * 8, (uint8_t *)&digestBlocks);
|
||||
}
|
||||
|
||||
// copy the digest out of the padded blocks
|
||||
memcpy(m_digest, &digestBlocks, sizeof(m_digest));
|
||||
}
|
||||
|
||||
//! \pre The image header must have already been read with a call to readImageHeader().
|
||||
//! \post The stream head is at the end of the image minus the last two cipher blocks.
|
||||
//! \param digest Where to store the resulting digest.
|
||||
//! \exception read_error Thrown if the image header is invalid.
|
||||
void EncoreBootImageReader::computeImageDigest(sha1_digest_t &digest)
|
||||
{
|
||||
m_stream.seekg(0, std::ios_base::beg);
|
||||
|
||||
CSHA1 hash;
|
||||
hash.Reset();
|
||||
|
||||
unsigned blockCount = m_header.m_imageBlocks - 2; // exclude digest at end of image
|
||||
while (blockCount--)
|
||||
{
|
||||
cipher_block_t block;
|
||||
if (m_stream.read((char *)&block, sizeof(block)).bad())
|
||||
{
|
||||
throw read_error("failed to read block while computing image digest");
|
||||
}
|
||||
hash.Update(block, sizeof(block));
|
||||
}
|
||||
|
||||
hash.Final();
|
||||
hash.GetHash(digest);
|
||||
}
|
||||
|
||||
//! \pre Image header must have been read before this method is called.
|
||||
//!
|
||||
void EncoreBootImageReader::readSectionTable()
|
||||
{
|
||||
// seek to the table
|
||||
m_stream.seekg(sizeOfCipherBlocks(m_header.m_headerBlocks), std::ios_base::beg);
|
||||
|
||||
unsigned sectionCount = m_header.m_sectionCount;
|
||||
while (sectionCount--)
|
||||
{
|
||||
EncoreBootImage::section_header_t header;
|
||||
if (m_stream.read((char *)&header, sizeof(header)).bad())
|
||||
{
|
||||
throw read_error("failed to read section header");
|
||||
}
|
||||
|
||||
// swizzle section header
|
||||
header.m_tag = ENDIAN_LITTLE_TO_HOST_U32(header.m_tag);
|
||||
header.m_offset = ENDIAN_LITTLE_TO_HOST_U32(header.m_offset);
|
||||
header.m_length = ENDIAN_LITTLE_TO_HOST_U32(header.m_length);
|
||||
header.m_flags = ENDIAN_LITTLE_TO_HOST_U32(header.m_flags);
|
||||
|
||||
m_sections.push_back(header);
|
||||
}
|
||||
}
|
||||
|
||||
//! Requires that an OTP key has been provided as the sole argument. Passing the
|
||||
//! key into this method lets the caller search the key dictionary for any number
|
||||
//! of keys and determine which are valid. If \a kek is found in the dictionary,
|
||||
//! the decrypted DEK is saved and true is returned. A result of false means
|
||||
//! that \a kek was not found.
|
||||
//!
|
||||
//! \pre The image header and section table must have been read already.
|
||||
//! \post The stream head points somewhere inside the key dictionary, or just after it.
|
||||
//! \post If the search was successful, the #m_dek member will contain the decrypted
|
||||
//! session key. Otherwise #m_dek is not modified.
|
||||
//! \param kek Search for this KEK in the dictionary.
|
||||
//! \retval true The DEK was found and decrypted. True is also returned when the
|
||||
//! image is not encrypted at all.
|
||||
//! \retval false No matching key entry was found. The image cannot be decrypted.
|
||||
bool EncoreBootImageReader::readKeyDictionary(const AESKey<128> &kek)
|
||||
{
|
||||
// do nothing if the image is not encrypted
|
||||
if (!isEncrypted())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// first compute a CBC-MAC over the image header with our KEK
|
||||
RijndaelCBCMAC mac(kek);
|
||||
mac.update((const uint8_t *)&m_header, sizeof(m_header));
|
||||
|
||||
// run the CBC-MAC over each entry in the section table too
|
||||
section_array_t::iterator it = m_sections.begin();
|
||||
for (; it != m_sections.end(); ++it)
|
||||
{
|
||||
mac.update((const uint8_t *)&(*it), sizeof(EncoreBootImage::section_header_t));
|
||||
}
|
||||
|
||||
// get the CBC-MAC result
|
||||
mac.finalize();
|
||||
const RijndaelCBCMAC::block_t &macResult = mac.getMAC();
|
||||
|
||||
// seek to the key dictionary
|
||||
m_stream.seekg(sizeOfCipherBlocks(m_header.m_keyDictionaryBlock), std::ios_base::beg);
|
||||
|
||||
// decipher each key entry
|
||||
unsigned entries = m_header.m_keyCount;
|
||||
while (entries--)
|
||||
{
|
||||
// read the entry
|
||||
EncoreBootImage::dek_dictionary_entry_t entry;
|
||||
if (m_stream.read((char *)&entry, sizeof(entry)).bad())
|
||||
{
|
||||
throw read_error("failed to read key dictionary entry");
|
||||
}
|
||||
|
||||
// compare the CBC-MAC we computed with the one in this entry
|
||||
if (memcmp(macResult, entry.m_mac, sizeof(cipher_block_t)) == 0)
|
||||
{
|
||||
// it's a match! now decrypt this entry's key in place
|
||||
Rijndael cipher;
|
||||
cipher.init(Rijndael::CBC, Rijndael::Decrypt, kek, Rijndael::Key16Bytes, m_header.m_iv);
|
||||
cipher.blockDecrypt(entry.m_dek, sizeof(entry.m_dek) * 8, entry.m_dek);
|
||||
|
||||
m_dek = entry.m_dek;
|
||||
memset(entry.m_dek, 0, sizeof(entry.m_dek)); // wipe the key value from memory
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// if we exit the loop normally then no matching MAC was found
|
||||
return false;
|
||||
}
|
||||
|
||||
//! Before the boot tag is added to the #m_bootTags member, some basic checks are performed.
|
||||
//! The command tag field is checked to make sure it matches #ROM_TAG_CMD. And
|
||||
//! the checksum field is verified to be sure it's correct.
|
||||
//!
|
||||
//! After the call to this method returns, the array of boot tags is accessible
|
||||
//! with the getBootTags() method. The array is sorted in the order in which
|
||||
//! the boot tags appeared in the image.
|
||||
//!
|
||||
//! \pre Image header must have been read.
|
||||
//! \pre Key dictionary must have been read and a valid DEK found.
|
||||
//! \post The stream head is left pointing just after the last boot tag.
|
||||
//! \exception read_error A failure to read the boot tag, or a failure on one
|
||||
//! of the consistency checks will cause this exception to be thrown.
|
||||
void EncoreBootImageReader::readBootTags()
|
||||
{
|
||||
assert(m_header.m_firstBootTagBlock != 0);
|
||||
|
||||
unsigned bootTagOffset = m_header.m_firstBootTagBlock;
|
||||
|
||||
while (1)
|
||||
{
|
||||
// seek to this boot tag and read it into a temporary buffer
|
||||
EncoreBootImage::boot_command_t header;
|
||||
m_stream.seekg(sizeOfCipherBlocks(bootTagOffset), std::ios_base::beg);
|
||||
if (m_stream.read((char *)&header, sizeof(header)).bad())
|
||||
{
|
||||
throw read_error("failed to read boot tag");
|
||||
}
|
||||
|
||||
// swizzle to command header
|
||||
header.m_flags = ENDIAN_LITTLE_TO_HOST_U16(header.m_flags);
|
||||
header.m_address = ENDIAN_LITTLE_TO_HOST_U32(header.m_address);
|
||||
header.m_count = ENDIAN_LITTLE_TO_HOST_U32(header.m_count);
|
||||
header.m_data = ENDIAN_LITTLE_TO_HOST_U32(header.m_data);
|
||||
|
||||
// decrypt in place
|
||||
if (isEncrypted())
|
||||
{
|
||||
Rijndael cipher;
|
||||
cipher.init(Rijndael::CBC, Rijndael::Decrypt, m_dek, Rijndael::Key16Bytes, m_header.m_iv);
|
||||
cipher.blockDecrypt((uint8_t *)&header, sizeof(header) * 8, (uint8_t *)&header);
|
||||
}
|
||||
|
||||
// perform some basic checks
|
||||
if (header.m_tag != EncoreBootImage::ROM_TAG_CMD)
|
||||
{
|
||||
throw read_error("boot tag is wrong command type");
|
||||
}
|
||||
|
||||
uint8_t checksum = calculateCommandChecksum(header);
|
||||
if (checksum != header.m_checksum)
|
||||
{
|
||||
throw read_error("boot tag checksum is invalid");
|
||||
}
|
||||
|
||||
// save this boot tag
|
||||
m_bootTags.push_back(header);
|
||||
|
||||
// and finally, update offset and break out of loop
|
||||
bootTagOffset += header.m_count + 1; // include this boot tag in offset
|
||||
if (header.m_flags & EncoreBootImage::ROM_LAST_TAG || bootTagOffset >= m_header.m_imageBlocks - 2)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t EncoreBootImageReader::calculateCommandChecksum(EncoreBootImage::boot_command_t &header)
|
||||
{
|
||||
uint8_t *bytes = reinterpret_cast<uint8_t *>(&header);
|
||||
uint8_t checksum = 0x5a;
|
||||
int i;
|
||||
|
||||
// start at one to skip checksum field
|
||||
for (i = 1; i < sizeof(header); ++i)
|
||||
{
|
||||
checksum += bytes[i];
|
||||
}
|
||||
|
||||
return checksum;
|
||||
}
|
||||
|
||||
//! \param index The index of the section to read.
|
||||
//!
|
||||
//! \pre Both the image header and section table must have been read already before
|
||||
//! calling this method.
|
||||
//! \exception read_error This exception is raised if the stream reports an error while
|
||||
//! trying to read from the section.
|
||||
EncoreBootImage::Section *EncoreBootImageReader::readSection(unsigned index)
|
||||
{
|
||||
// look up section header
|
||||
assert(index < m_sections.size());
|
||||
EncoreBootImage::section_header_t &header = m_sections[index];
|
||||
|
||||
// seek to the section
|
||||
m_stream.seekg(sizeOfCipherBlocks(header.m_offset), std::ios_base::beg);
|
||||
|
||||
uint8_t *contents = NULL;
|
||||
try
|
||||
{
|
||||
// allocate memory for the section contents and read the whole thing
|
||||
unsigned contentLength = sizeOfCipherBlocks(header.m_length);
|
||||
contents = new uint8_t[contentLength];
|
||||
if (m_stream.read((char *)contents, contentLength).bad())
|
||||
{
|
||||
throw read_error("failed to read section");
|
||||
}
|
||||
|
||||
// decrypt the entire section at once, if the image is encrypted and
|
||||
// the cleartext flag is not set
|
||||
if (isEncrypted() && (header.m_flags & EncoreBootImage::ROM_SECTION_CLEARTEXT) == 0)
|
||||
{
|
||||
Rijndael cipher;
|
||||
cipher.init(Rijndael::CBC, Rijndael::Decrypt, m_dek, Rijndael::Key16Bytes, m_header.m_iv);
|
||||
cipher.blockDecrypt(contents, contentLength * 8, contents);
|
||||
}
|
||||
|
||||
// create section object
|
||||
EncoreBootImage::Section *resultSection = NULL;
|
||||
if (header.m_flags & EncoreBootImage::ROM_SECTION_BOOTABLE)
|
||||
{
|
||||
// a boot command section.
|
||||
EncoreBootImage::BootSection *bootSection = new EncoreBootImage::BootSection(header.m_tag);
|
||||
|
||||
bootSection->fillFromData((cipher_block_t *)contents, header.m_length);
|
||||
|
||||
resultSection = bootSection;
|
||||
}
|
||||
else
|
||||
{
|
||||
// this is a raw data section
|
||||
EncoreBootImage::DataSection *dataSection = new EncoreBootImage::DataSection(header.m_tag);
|
||||
dataSection->setDataNoCopy(contents, contentLength);
|
||||
contents = NULL;
|
||||
resultSection = dataSection;
|
||||
}
|
||||
|
||||
return resultSection;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
if (contents)
|
||||
{
|
||||
delete[] contents;
|
||||
}
|
||||
throw;
|
||||
}
|
||||
}
|
||||
117
apps/elftosb/common/EncoreBootImageReader.h
Normal file
117
apps/elftosb/common/EncoreBootImageReader.h
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* File: EncoreBootImageReader.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
#if !defined(_EncoreBootImageReader_h_)
|
||||
#define _EncoreBootImageReader_h_
|
||||
|
||||
#include "EncoreBootImage.h"
|
||||
|
||||
namespace elftosb
|
||||
{
|
||||
/*!
|
||||
* \brief Reads a Piano/Encore boot image from an input stream.
|
||||
*/
|
||||
class EncoreBootImageReader
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* \brief Exception class used for error found while reading a boot image.
|
||||
*/
|
||||
class read_error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
//! \brief Constructor.
|
||||
read_error(const std::string &msg)
|
||||
: std::runtime_error(msg)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
//! \brief An array of section headers.
|
||||
typedef std::vector<EncoreBootImage::section_header_t> section_array_t;
|
||||
|
||||
//! \brief An array of boot tags.
|
||||
typedef std::vector<EncoreBootImage::boot_command_t> boot_tag_array_t;
|
||||
|
||||
public:
|
||||
//! \brief Default constructor.
|
||||
EncoreBootImageReader(std::istream &stream)
|
||||
: m_stream(stream)
|
||||
{
|
||||
}
|
||||
|
||||
//! \brief Destructor.
|
||||
virtual ~EncoreBootImageReader() {}
|
||||
//! \name Decryption key
|
||||
//! These methods provide access to the Data Encryption Key (DEK). Normally
|
||||
//! the DEK is discovered using the readKeyDictionary() method.
|
||||
//@{
|
||||
inline void setKey(const AESKey<128> &key) { m_dek = key; }
|
||||
inline const AESKey<128> &getKey() const { return m_dek; }
|
||||
//@}
|
||||
|
||||
//! \name Readers
|
||||
//! This group of methods is responsible for reading and parsing different
|
||||
//! pieces and parts of the boot image file.
|
||||
//@{
|
||||
//! \brief Reads the header from the image.
|
||||
void readImageHeader();
|
||||
|
||||
//! \brief Computes the actual SHA-1 digest of the image header.
|
||||
void computeHeaderDigest(sha1_digest_t &digest);
|
||||
|
||||
//! \brief Reads the digest at the end of the image.
|
||||
void readImageDigest();
|
||||
|
||||
//! \brief Run a SHA-1 digest over the entire image.
|
||||
void computeImageDigest(sha1_digest_t &digest);
|
||||
|
||||
//! \brief Read the plaintext section table entries.
|
||||
void readSectionTable();
|
||||
|
||||
//! \brief Reads the key dictionary, if the image is encrypted.
|
||||
bool readKeyDictionary(const AESKey<128> &kek);
|
||||
|
||||
//! \brief
|
||||
void readBootTags();
|
||||
|
||||
//! \brief
|
||||
EncoreBootImage::Section *readSection(unsigned index);
|
||||
//@}
|
||||
|
||||
//! \name Accessors
|
||||
//! Information retrieved with reader methods is accessible through
|
||||
//! these methods.
|
||||
//@{
|
||||
//! \brief Returns whether the image is encrypted or not.
|
||||
//! \pre The header must have been read already.
|
||||
inline bool isEncrypted() const { return m_header.m_keyCount > 0; }
|
||||
//! \brief Returns a reference to the image's header.
|
||||
const EncoreBootImage::boot_image_header_t &getHeader() const { return m_header; }
|
||||
//! \brief Returns a reference to the SHA-1 digest read from the image.
|
||||
const sha1_digest_t &getDigest() const { return m_digest; }
|
||||
//! \brief Returns a reference to the STL container holding the section headers.
|
||||
inline const section_array_t &getSections() const { return m_sections; }
|
||||
//! \brief Returns a reference to the STL container holding the boot tags.
|
||||
inline const boot_tag_array_t &getBootTags() const { return m_bootTags; }
|
||||
//@}
|
||||
|
||||
protected:
|
||||
std::istream &m_stream; //!< The input stream to read the image from.
|
||||
AESKey<128> m_dek; //!< DEK (data encryption key) read from the key dictionary.
|
||||
EncoreBootImage::boot_image_header_t m_header; //!< Header from the boot image.
|
||||
sha1_digest_t m_digest; //!< SHA-1 digest as read from the image.
|
||||
section_array_t m_sections; //!< The section table.
|
||||
boot_tag_array_t m_bootTags; //!< The array of boot tags read from the image.
|
||||
|
||||
protected:
|
||||
//! \brief Calculates the 8-bit checksum on a boot command header.
|
||||
uint8_t calculateCommandChecksum(EncoreBootImage::boot_command_t &header);
|
||||
};
|
||||
|
||||
}; // namespace elftosb
|
||||
|
||||
#endif // _EncoreBootImageReader_h_
|
||||
149
apps/elftosb/common/EndianUtilities.h
Normal file
149
apps/elftosb/common/EndianUtilities.h
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* File: EndianUtilities.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
#if !defined(_EndianUtilities_h_)
|
||||
#define _EndianUtilities_h_
|
||||
|
||||
//! \name Swap macros
|
||||
//! These macros always swap the data.
|
||||
//@{
|
||||
|
||||
//! Byte swap 16-bit value.
|
||||
#define _BYTESWAP16(value) (((((uint16_t)value) << 8) & 0xFF00) | ((((uint16_t)value) >> 8) & 0x00FF))
|
||||
|
||||
//! Byte swap 32-bit value.
|
||||
#define _BYTESWAP32(value) \
|
||||
(((((uint32_t)value) << 24) & 0xFF000000) | ((((uint32_t)value) << 8) & 0x00FF0000) | \
|
||||
((((uint32_t)value) >> 8) & 0x0000FF00) | ((((uint32_t)value) >> 24) & 0x000000FF))
|
||||
|
||||
//! Byte swap 64-bit value.
|
||||
#define _BYTESWAP64(value) \
|
||||
(((((uint64_t)value) << 56) & 0xFF00000000000000ULL) | ((((uint64_t)value) << 40) & 0x00FF000000000000ULL) | \
|
||||
((((uint64_t)value) << 24) & 0x0000FF0000000000ULL) | ((((uint64_t)value) << 8) & 0x000000FF00000000ULL) | \
|
||||
((((uint64_t)value) >> 8) & 0x00000000FF000000ULL) | ((((uint64_t)value) >> 24) & 0x0000000000FF0000ULL) | \
|
||||
((((uint64_t)value) >> 40) & 0x000000000000FF00ULL) | ((((uint64_t)value) >> 56) & 0x00000000000000FFULL))
|
||||
|
||||
//@}
|
||||
|
||||
//! \name Inline swap functions
|
||||
//@{
|
||||
|
||||
inline uint16_t _swap_u16(uint16_t value)
|
||||
{
|
||||
return _BYTESWAP16(value);
|
||||
}
|
||||
inline int16_t _swap_s16(int16_t value)
|
||||
{
|
||||
return (int16_t)_BYTESWAP16((uint16_t)value);
|
||||
}
|
||||
|
||||
inline uint32_t _swap_u32(uint32_t value)
|
||||
{
|
||||
return _BYTESWAP32(value);
|
||||
}
|
||||
inline int32_t _swap_s32(int32_t value)
|
||||
{
|
||||
return (int32_t)_BYTESWAP32((uint32_t)value);
|
||||
}
|
||||
|
||||
inline uint64_t _swap_u64(uint64_t value)
|
||||
{
|
||||
return _BYTESWAP64(value);
|
||||
}
|
||||
inline int64_t _swap_s64(int64_t value)
|
||||
{
|
||||
return (uint64_t)_BYTESWAP64((uint64_t)value);
|
||||
}
|
||||
|
||||
//@}
|
||||
|
||||
#if defined(__LITTLE_ENDIAN__)
|
||||
|
||||
/* little endian host */
|
||||
|
||||
#define ENDIAN_BIG_TO_HOST_U16(value) (_swap_u16(value))
|
||||
#define ENDIAN_HOST_TO_BIG_U16(value) (_swap_u16(value))
|
||||
|
||||
#define ENDIAN_BIG_TO_HOST_S16(value) (_swap_s16(value))
|
||||
#define ENDIAN_HOST_TO_BIG_S16(value) (_swap_s16(value))
|
||||
|
||||
#define ENDIAN_BIG_TO_HOST_U32(value) (_swap_u32(value))
|
||||
#define ENDIAN_HOST_TO_BIG_U32(value) (_swap_u32(value))
|
||||
|
||||
#define ENDIAN_BIG_TO_HOST_S32(value) (_swap_s32(value))
|
||||
#define ENDIAN_HOST_TO_BIG_S32(value) (_swap_s32(value))
|
||||
|
||||
#define ENDIAN_BIG_TO_HOST_U64(value) (_swap_u64(value))
|
||||
#define ENDIAN_HOST_TO_BIG_U64(value) (_swap_u64(value))
|
||||
|
||||
#define ENDIAN_BIG_TO_HOST_S64(value) (_swap_s64(value))
|
||||
#define ENDIAN_HOST_TO_BIG_S64(value) (_swap_s64(value))
|
||||
|
||||
/* no-ops */
|
||||
|
||||
#define ENDIAN_LITTLE_TO_HOST_U16(value) (value)
|
||||
#define ENDIAN_HOST_TO_LITTLE_U16(value) (value)
|
||||
|
||||
#define ENDIAN_LITTLE_TO_HOST_S16(value) (value)
|
||||
#define ENDIAN_HOST_TO_LITTLE_S16(value) (value)
|
||||
|
||||
#define ENDIAN_LITTLE_TO_HOST_U32(value) (value)
|
||||
#define ENDIAN_HOST_TO_LITTLE_U32(value) (value)
|
||||
|
||||
#define ENDIAN_LITTLE_TO_HOST_S32(value) (value)
|
||||
#define ENDIAN_HOST_TO_LITTLE_S32(value) (value)
|
||||
|
||||
#define ENDIAN_LITTLE_TO_HOST_U64(value) (value)
|
||||
#define ENDIAN_HOST_TO_LITTLE_U64(value) (value)
|
||||
|
||||
#define ENDIAN_LITTLE_TO_HOST_S64(value) (value)
|
||||
#define ENDIAN_HOST_TO_LITTLE_S64(value) (value)
|
||||
|
||||
#elif defined(__BIG_ENDIAN__)
|
||||
|
||||
/* big endian host */
|
||||
|
||||
#define ENDIAN_LITTLE_TO_HOST_U16(value) (_swap_u16(value))
|
||||
#define ENDIAN_HOST_TO_LITTLE_U16(value) (_swap_u16(value))
|
||||
|
||||
#define ENDIAN_LITTLE_TO_HOST_S16(value) (_swap_s16(value))
|
||||
#define ENDIAN_HOST_TO_LITTLE_S16(value) (_swap_s16(value))
|
||||
|
||||
#define ENDIAN_LITTLE_TO_HOST_U32(value) (_swap_u32(value))
|
||||
#define ENDIAN_HOST_TO_LITTLE_U32(value) (_swap_u32(value))
|
||||
|
||||
#define ENDIAN_LITTLE_TO_HOST_S32(value) (_swap_s32(value))
|
||||
#define ENDIAN_HOST_TO_LITTLE_S32(value) (_swap_s32(value))
|
||||
|
||||
#define ENDIAN_LITTLE_TO_HOST_U64(value) (_swap_u64(value))
|
||||
#define ENDIAN_HOST_TO_LITTLE_U64(value) (_swap_u64(value))
|
||||
|
||||
#define ENDIAN_LITTLE_TO_HOST_S64(value) (_swap_s64(value))
|
||||
#define ENDIAN_HOST_TO_LITTLE_S64(value) (_swap_s64(value))
|
||||
|
||||
/* no-ops */
|
||||
|
||||
#define ENDIAN_BIG_TO_HOST_U16(value) (value)
|
||||
#define ENDIAN_HOST_TO_BIG_U16(value) (value)
|
||||
|
||||
#define ENDIAN_BIG_TO_HOST_S16(value) (value)
|
||||
#define ENDIAN_HOST_TO_BIG_S16(value) (value)
|
||||
|
||||
#define ENDIAN_BIG_TO_HOST_U32(value) (value)
|
||||
#define ENDIAN_HOST_TO_BIG_U32(value) (value)
|
||||
|
||||
#define ENDIAN_BIG_TO_HOST_S32(value) (value)
|
||||
#define ENDIAN_HOST_TO_BIG_S32(value) (value)
|
||||
|
||||
#define ENDIAN_BIG_TO_HOST_U64(value) (value)
|
||||
#define ENDIAN_HOST_TO_BIG_U64(value) (value)
|
||||
|
||||
#define ENDIAN_BIG_TO_HOST_S64(value) (value)
|
||||
#define ENDIAN_HOST_TO_BIG_S64(value) (value)
|
||||
|
||||
#endif
|
||||
|
||||
#endif // _EndianUtilities_h_
|
||||
110
apps/elftosb/common/EvalContext.cpp
Normal file
110
apps/elftosb/common/EvalContext.cpp
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* File: EvalContext.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
|
||||
#include "EvalContext.h"
|
||||
#include <stdexcept>
|
||||
#include "format_string.h"
|
||||
|
||||
using namespace elftosb;
|
||||
|
||||
EvalContext::EvalContext()
|
||||
: m_sourcesManager(0)
|
||||
{
|
||||
}
|
||||
|
||||
EvalContext::~EvalContext()
|
||||
{
|
||||
}
|
||||
|
||||
bool EvalContext::isVariableDefined(const std::string &name)
|
||||
{
|
||||
variable_map_t::const_iterator it = m_variables.find(name);
|
||||
return it != m_variables.end();
|
||||
}
|
||||
|
||||
uint32_t EvalContext::getVariableValue(const std::string &name)
|
||||
{
|
||||
variable_map_t::const_iterator it = m_variables.find(name);
|
||||
if (it == m_variables.end())
|
||||
{
|
||||
throw std::runtime_error(format_string("undefined variable '%s'", name.c_str()));
|
||||
}
|
||||
|
||||
return it->second.m_value;
|
||||
}
|
||||
|
||||
int_size_t EvalContext::getVariableSize(const std::string &name)
|
||||
{
|
||||
variable_map_t::const_iterator it = m_variables.find(name);
|
||||
if (it == m_variables.end())
|
||||
{
|
||||
throw std::runtime_error(format_string("undefined variable '%s'", name.c_str()));
|
||||
}
|
||||
|
||||
return it->second.m_size;
|
||||
}
|
||||
|
||||
void EvalContext::setVariable(const std::string &name, uint32_t value, int_size_t size)
|
||||
{
|
||||
// check if var is locked
|
||||
variable_map_t::const_iterator it = m_variables.find(name);
|
||||
if (it != m_variables.end() && it->second.m_isLocked)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// set var info
|
||||
variable_info_t info;
|
||||
info.m_value = value;
|
||||
info.m_size = size;
|
||||
info.m_isLocked = false;
|
||||
m_variables[name] = info;
|
||||
}
|
||||
|
||||
bool EvalContext::isVariableLocked(const std::string &name)
|
||||
{
|
||||
variable_map_t::const_iterator it = m_variables.find(name);
|
||||
if (it == m_variables.end())
|
||||
{
|
||||
throw std::runtime_error(format_string("undefined variable '%s'", name.c_str()));
|
||||
}
|
||||
|
||||
return it->second.m_isLocked;
|
||||
}
|
||||
|
||||
void EvalContext::lockVariable(const std::string &name)
|
||||
{
|
||||
variable_map_t::iterator it = m_variables.find(name);
|
||||
if (it == m_variables.end())
|
||||
{
|
||||
throw std::runtime_error(format_string("undefined variable '%s'", name.c_str()));
|
||||
}
|
||||
|
||||
it->second.m_isLocked = true;
|
||||
}
|
||||
|
||||
void EvalContext::unlockVariable(const std::string &name)
|
||||
{
|
||||
variable_map_t::iterator it = m_variables.find(name);
|
||||
if (it == m_variables.end())
|
||||
{
|
||||
throw std::runtime_error("undefined variable");
|
||||
}
|
||||
|
||||
it->second.m_isLocked = false;
|
||||
}
|
||||
|
||||
void EvalContext::dump()
|
||||
{
|
||||
variable_map_t::iterator it = m_variables.begin();
|
||||
for (; it != m_variables.end(); ++it)
|
||||
{
|
||||
variable_info_t &info = it->second;
|
||||
const char *lockedString = info.m_isLocked ? "locked" : "unlocked";
|
||||
printf("%s = %u:%d (%s)\n", it->first.c_str(), info.m_value, (int)info.m_size, lockedString);
|
||||
}
|
||||
}
|
||||
97
apps/elftosb/common/EvalContext.h
Normal file
97
apps/elftosb/common/EvalContext.h
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* File: EvalContext.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
#if !defined(_EvalContext_h_)
|
||||
#define _EvalContext_h_
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include "Value.h"
|
||||
#include "int_size.h"
|
||||
#include "SourceFile.h"
|
||||
|
||||
namespace elftosb
|
||||
{
|
||||
/*!
|
||||
* \brief Context for evaluating AST tree and expressions.
|
||||
*
|
||||
* Keeps a map of variable names to integer values. Each integer value has a
|
||||
* size attribute in addition to the actual value. Variables can be locked, which
|
||||
* simply means that they cannot be assigned a new value.
|
||||
*
|
||||
* \todo Switch to using Value instances to keep track of variable values. This
|
||||
* will enable variables to have string values, for one.
|
||||
*/
|
||||
class EvalContext
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* \brief Abstract interface for a manager of source files.
|
||||
*/
|
||||
class SourceFileManager
|
||||
{
|
||||
public:
|
||||
//! \brief Returns true if a source file with the name \a name exists.
|
||||
virtual bool hasSourceFile(const std::string &name) = 0;
|
||||
|
||||
//! \brief Gets the requested source file.
|
||||
virtual SourceFile *getSourceFile(const std::string &name) = 0;
|
||||
|
||||
//! \brief Returns the default source file, or NULL if none is set.
|
||||
virtual SourceFile *getDefaultSourceFile() = 0;
|
||||
};
|
||||
|
||||
public:
|
||||
//! \brief Constructor.
|
||||
EvalContext();
|
||||
|
||||
//! \brief Destructor.
|
||||
virtual ~EvalContext();
|
||||
|
||||
//! \name Source file manager
|
||||
//@{
|
||||
//! \brief
|
||||
void setSourceFileManager(SourceFileManager *manager) { m_sourcesManager = manager; }
|
||||
//! \brief
|
||||
SourceFileManager *getSourceFileManager() { return m_sourcesManager; }
|
||||
//@}
|
||||
|
||||
//! \name Variables
|
||||
//@{
|
||||
bool isVariableDefined(const std::string &name);
|
||||
uint32_t getVariableValue(const std::string &name);
|
||||
int_size_t getVariableSize(const std::string &name);
|
||||
void setVariable(const std::string &name, uint32_t value, int_size_t size = kWordSize);
|
||||
//@}
|
||||
|
||||
//! \name Locks
|
||||
//@{
|
||||
bool isVariableLocked(const std::string &name);
|
||||
void lockVariable(const std::string &name);
|
||||
void unlockVariable(const std::string &name);
|
||||
//@}
|
||||
|
||||
void dump();
|
||||
|
||||
protected:
|
||||
//! Information about a variable's value.
|
||||
struct variable_info_t
|
||||
{
|
||||
uint32_t m_value; //!< Variable value.
|
||||
int_size_t m_size; //!< Number of bytes
|
||||
bool m_isLocked; //!< Can this variable's value be changed?
|
||||
};
|
||||
|
||||
//! Type to maps between the variable name and its info.
|
||||
typedef std::map<std::string, variable_info_t> variable_map_t;
|
||||
|
||||
SourceFileManager *m_sourcesManager; //!< Interface to source file manager.
|
||||
variable_map_t m_variables; //!< Map of variables to their final values.
|
||||
};
|
||||
|
||||
}; // namespace elftosb
|
||||
|
||||
#endif // _EvalContext_h_
|
||||
87
apps/elftosb/common/ExcludesListMatcher.cpp
Normal file
87
apps/elftosb/common/ExcludesListMatcher.cpp
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* File: ExcludesListMatcher.cpp
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
|
||||
#include "ExcludesListMatcher.h"
|
||||
|
||||
using namespace elftosb;
|
||||
|
||||
ExcludesListMatcher::ExcludesListMatcher()
|
||||
: GlobMatcher("")
|
||||
{
|
||||
}
|
||||
|
||||
ExcludesListMatcher::~ExcludesListMatcher()
|
||||
{
|
||||
}
|
||||
|
||||
//! \param isInclude True if this pattern is an include, false if it is an exclude.
|
||||
//! \param pattern String containing the glob pattern.
|
||||
void ExcludesListMatcher::addPattern(bool isInclude, const std::string &pattern)
|
||||
{
|
||||
glob_list_item_t item;
|
||||
item.m_isInclude = isInclude;
|
||||
item.m_glob = pattern;
|
||||
|
||||
// add to end of list
|
||||
m_patterns.push_back(item);
|
||||
}
|
||||
|
||||
//! If there are no entries in the match list, the match fails.
|
||||
//!
|
||||
//! \param testValue The string to match against the pattern list.
|
||||
//! \retval true The \a testValue argument matches.
|
||||
//! \retval false No match was made against the argument.
|
||||
bool ExcludesListMatcher::match(const std::string &testValue)
|
||||
{
|
||||
if (!m_patterns.size())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Iterate over the match list. Includes act as an OR operator, while
|
||||
// excludes act as an AND operator.
|
||||
bool didMatch = false;
|
||||
bool isFirstItem = true;
|
||||
glob_list_t::iterator it = m_patterns.begin();
|
||||
for (; it != m_patterns.end(); ++it)
|
||||
{
|
||||
glob_list_item_t &item = *it;
|
||||
|
||||
// if this pattern is an include and it doesn't match, or
|
||||
// if this pattern is an exclude and it does match, then the match fails
|
||||
bool didItemMatch = globMatch(testValue.c_str(), item.m_glob.c_str());
|
||||
|
||||
if (item.m_isInclude)
|
||||
{
|
||||
// Include
|
||||
if (isFirstItem)
|
||||
{
|
||||
didMatch = didItemMatch;
|
||||
}
|
||||
else
|
||||
{
|
||||
didMatch = didMatch || didItemMatch;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Exclude
|
||||
if (isFirstItem)
|
||||
{
|
||||
didMatch = !didItemMatch;
|
||||
}
|
||||
else
|
||||
{
|
||||
didMatch = didMatch && !didItemMatch;
|
||||
}
|
||||
}
|
||||
|
||||
isFirstItem = false;
|
||||
}
|
||||
|
||||
return didMatch;
|
||||
}
|
||||
66
apps/elftosb/common/ExcludesListMatcher.h
Normal file
66
apps/elftosb/common/ExcludesListMatcher.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* File: ExcludesListMatcher.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
#if !defined(_ExcludesListMatcher_h_)
|
||||
#define _ExcludesListMatcher_h_
|
||||
|
||||
#include "GlobMatcher.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace elftosb
|
||||
{
|
||||
/*!
|
||||
* \brief Matches strings using a series of include and exclude glob patterns.
|
||||
*
|
||||
* This string matcher class uses a sequential, ordered list of glob patterns to
|
||||
* determine whether a string matches. Attached to each pattern is an include/exclude
|
||||
* action. The patterns in the list effectively form a Boolean expression. Includes
|
||||
* act as an OR operator while excludes act as an AND NOT operator.
|
||||
*
|
||||
* Examples (plus prefix is include, minus prefix is exclude):
|
||||
* - +foo: foo
|
||||
* - -foo: !foo
|
||||
* - +foo, +bar: foo || bar
|
||||
* - +foo, -bar: foo && !bar
|
||||
* - +foo, -bar, +baz: foo && !bar || baz
|
||||
*
|
||||
* The only reason for inheriting from GlobMatcher is so we can access the protected
|
||||
* globMatch() method.
|
||||
*/
|
||||
class ExcludesListMatcher : public GlobMatcher
|
||||
{
|
||||
public:
|
||||
//! \brief Default constructor.
|
||||
ExcludesListMatcher();
|
||||
|
||||
//! \brief Destructor.
|
||||
~ExcludesListMatcher();
|
||||
|
||||
//! \name Pattern list
|
||||
//@{
|
||||
//! \brief Add one include or exclude pattern to the end of the match list.
|
||||
void addPattern(bool isInclude, const std::string &pattern);
|
||||
//@}
|
||||
|
||||
//! \brief Performs a single string match test against testValue.
|
||||
virtual bool match(const std::string &testValue);
|
||||
|
||||
protected:
|
||||
//! \brief Information about one glob pattern entry in a match list.
|
||||
struct glob_list_item_t
|
||||
{
|
||||
bool m_isInclude; //!< True if include, false if exclude.
|
||||
std::string m_glob; //!< The glob pattern to match.
|
||||
};
|
||||
|
||||
typedef std::vector<glob_list_item_t> glob_list_t;
|
||||
glob_list_t m_patterns; //!< Ordered list of include and exclude patterns.
|
||||
};
|
||||
|
||||
}; // namespace elftosb
|
||||
|
||||
#endif // _ExcludesListMatcher_h_
|
||||
103
apps/elftosb/common/GHSSecInfo.cpp
Normal file
103
apps/elftosb/common/GHSSecInfo.cpp
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* File: GHSSecInfo.cpp
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
|
||||
#include "GHSSecInfo.h"
|
||||
#include <stdexcept>
|
||||
#include "Logging.h"
|
||||
#include "EndianUtilities.h"
|
||||
|
||||
//! The name of the GHS-specific section info table ELF section.
|
||||
const char *const kSecInfoSectionName = ".secinfo";
|
||||
|
||||
using namespace elftosb;
|
||||
|
||||
//! The ELF file passed into this constructor as the \a elf argument must remain
|
||||
//! valid for the life of this object.
|
||||
//!
|
||||
//! \param elf The ELF file parser. An assertion is raised if this is NULL.
|
||||
GHSSecInfo::GHSSecInfo(StELFFile *elf)
|
||||
: m_elf(elf)
|
||||
, m_hasInfo(false)
|
||||
, m_info(0)
|
||||
, m_entryCount(0)
|
||||
{
|
||||
assert(elf);
|
||||
|
||||
// look up the section. if it's not there just leave m_info and m_entryCount to 0
|
||||
unsigned sectionIndex = m_elf->getIndexOfSectionWithName(kSecInfoSectionName);
|
||||
if (sectionIndex == SHN_UNDEF)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// get the section data
|
||||
const Elf32_Shdr &secInfo = m_elf->getSectionAtIndex(sectionIndex);
|
||||
if (secInfo.sh_type != SHT_PROGBITS)
|
||||
{
|
||||
// .secinfo section isn't the right type, so something is wrong
|
||||
return;
|
||||
}
|
||||
|
||||
m_hasInfo = true;
|
||||
m_info = (ghs_secinfo_t *)m_elf->getSectionDataAtIndex(sectionIndex);
|
||||
m_entryCount = secInfo.sh_size / sizeof(ghs_secinfo_t);
|
||||
}
|
||||
|
||||
//! Looks up \a addr for \a length in the .secinfo array. Only if that address is in the
|
||||
//! .secinfo array does this section need to be filled. If the section is found but the
|
||||
//! length does not match the \a length argument, a message is logged at the
|
||||
//! #Logger::WARNING level.
|
||||
//!
|
||||
//! If the .secinfo section is not present in the ELF file, this method always returns
|
||||
//! true.
|
||||
//!
|
||||
//! \param addr The start address of the section to query.
|
||||
//! \param length The length of the section. If a section with a start address matching
|
||||
//! \a addr is found, its length must match \a length to be considered.
|
||||
//!
|
||||
//! \retval true The section matching \a addr and \a length was found and should be filled.
|
||||
//! True is also returned when the ELF file does not have a .secinfo section.
|
||||
//! \retval false The section was not found and should not be filled.
|
||||
bool GHSSecInfo::isSectionFilled(uint32_t addr, uint32_t length)
|
||||
{
|
||||
if (!m_hasInfo)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned i;
|
||||
for (i = 0; i < m_entryCount; ++i)
|
||||
{
|
||||
// byte swap these values into host endianness
|
||||
uint32_t clearAddr = ENDIAN_LITTLE_TO_HOST_U32(m_info[i].m_clearAddr);
|
||||
uint32_t numBytesToClear = ENDIAN_LITTLE_TO_HOST_U32(m_info[i].m_numBytesToClear);
|
||||
|
||||
// we only consider non-zero length clear regions
|
||||
if ((addr == clearAddr) && (numBytesToClear != 0))
|
||||
{
|
||||
// it is an error if the address matches but the length does not
|
||||
if (length != numBytesToClear)
|
||||
{
|
||||
Log::log(Logger::WARNING, "ELF Error: Size mismatch @ sect=%u, .secinfo=%u at addr 0x%08X\n", length,
|
||||
numBytesToClear, addr);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//! Simply calls through to isSectionFilled(uint32_t, uint32_t) to determine
|
||||
//! if \a section should be filled.
|
||||
//!
|
||||
//! If the .secinfo section is not present in the ELF file, this method always returns
|
||||
//! true.
|
||||
bool GHSSecInfo::isSectionFilled(const Elf32_Shdr §ion)
|
||||
{
|
||||
return isSectionFilled(section.sh_addr, section.sh_size);
|
||||
}
|
||||
70
apps/elftosb/common/GHSSecInfo.h
Normal file
70
apps/elftosb/common/GHSSecInfo.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* File: GHSSecInfo.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
#if !defined(_GHSSecInfo_h_)
|
||||
#define _GHSSecInfo_h_
|
||||
|
||||
#include "StELFFile.h"
|
||||
#include "smart_ptr.h"
|
||||
|
||||
namespace elftosb
|
||||
{
|
||||
/*!
|
||||
* \brief Wrapper around the GHS-specific .secinfo ELF section.
|
||||
*
|
||||
* ELF files produced by the Green Hills MULTI toolset will have a
|
||||
* special .secinfo section. For the most part, this section contains
|
||||
* a list of address
|
||||
* ranges that should be filled by the C runtime startup code. The
|
||||
* address ranges correspond to those of ELF sections whose type is
|
||||
* #SHT_NOBITS. The GHS runtime uses this table instead of just filling
|
||||
* all #SHT_NOBITS sections because the linker command file can
|
||||
* be used to optionally not fill individual sections.
|
||||
*
|
||||
* The isSectionFilled() methods let calling code determine if an ELF
|
||||
* section is found in the .secinfo table. If the section is found,
|
||||
* then it should be filled.
|
||||
*/
|
||||
class GHSSecInfo
|
||||
{
|
||||
public:
|
||||
//! \brief Default constructor.
|
||||
GHSSecInfo(StELFFile *elf);
|
||||
|
||||
//! \brief Returns true if there is a .secinfo section present in the ELF file.
|
||||
bool hasSecinfo() const { return m_hasInfo; }
|
||||
//! \brief Determines if a section should be filled.
|
||||
bool isSectionFilled(uint32_t addr, uint32_t length);
|
||||
|
||||
//! \brief Determines if \a section should be filled.
|
||||
bool isSectionFilled(const Elf32_Shdr §ion);
|
||||
|
||||
protected:
|
||||
#pragma pack(1)
|
||||
|
||||
/*!
|
||||
* \brief The structure of one .secinfo entry.
|
||||
*/
|
||||
struct ghs_secinfo_t
|
||||
{
|
||||
uint32_t m_clearAddr; //!< Address to start filling from.
|
||||
uint32_t m_clearValue; //!< Value to fill with.
|
||||
uint32_t m_numBytesToClear; //!< Number of bytes to fill.
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
|
||||
protected:
|
||||
StELFFile *m_elf; //!< The parser object for our ELF file.
|
||||
bool m_hasInfo; //!< Whether .secinfo is present in the ELF file.
|
||||
smart_array_ptr<ghs_secinfo_t>
|
||||
m_info; //!< Pointer to the .secinfo entries. Will be NULL if there is no .secinfo section in the file.
|
||||
unsigned m_entryCount; //!< Number of entries in #m_info.
|
||||
};
|
||||
|
||||
}; // namespace elftosb
|
||||
|
||||
#endif // _GHSSecInfo_h_
|
||||
135
apps/elftosb/common/GlobMatcher.cpp
Normal file
135
apps/elftosb/common/GlobMatcher.cpp
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* File: GlobMatcher.cpp
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
|
||||
#include "GlobMatcher.h"
|
||||
|
||||
#ifndef NEGATE
|
||||
#define NEGATE '^' // std cset negation char
|
||||
#endif
|
||||
|
||||
using namespace elftosb;
|
||||
|
||||
//! The glob pattern must match the \e entire test value argument in order
|
||||
//! for the match to be considered successful. Thus, even if, for example,
|
||||
//! the pattern matches all but the last character the result will be false.
|
||||
//!
|
||||
//! \retval true The test value does match the glob pattern.
|
||||
//! \retval false The test value does not match the glob pattern.
|
||||
bool GlobMatcher::match(const std::string &testValue)
|
||||
{
|
||||
return globMatch(testValue.c_str(), m_pattern.c_str());
|
||||
}
|
||||
|
||||
//! \note This glob implementation was originally written by ozan s. yigit in
|
||||
//! December 1994. This is public domain source code.
|
||||
bool GlobMatcher::globMatch(const char *str, const char *p)
|
||||
{
|
||||
int negate;
|
||||
int match;
|
||||
int c;
|
||||
|
||||
while (*p)
|
||||
{
|
||||
if (!*str && *p != '*')
|
||||
return false;
|
||||
|
||||
switch (c = *p++)
|
||||
{
|
||||
case '*':
|
||||
while (*p == '*')
|
||||
p++;
|
||||
|
||||
if (!*p)
|
||||
return true;
|
||||
|
||||
if (*p != '?' && *p != '[' && *p != '\\')
|
||||
while (*str && *p != *str)
|
||||
str++;
|
||||
|
||||
while (*str)
|
||||
{
|
||||
if (globMatch(str, p))
|
||||
return true;
|
||||
str++;
|
||||
}
|
||||
return false;
|
||||
|
||||
case '?':
|
||||
if (*str)
|
||||
break;
|
||||
return false;
|
||||
|
||||
// set specification is inclusive, that is [a-z] is a, z and
|
||||
// everything in between. this means [z-a] may be interpreted
|
||||
// as a set that contains z, a and nothing in between.
|
||||
case '[':
|
||||
if (*p != NEGATE)
|
||||
negate = false;
|
||||
else
|
||||
{
|
||||
negate = true;
|
||||
p++;
|
||||
}
|
||||
|
||||
match = false;
|
||||
|
||||
while (!match && (c = *p++))
|
||||
{
|
||||
if (!*p)
|
||||
return false;
|
||||
if (*p == '-')
|
||||
{ // c-c
|
||||
if (!*++p)
|
||||
return false;
|
||||
if (*p != ']')
|
||||
{
|
||||
if (*str == c || *str == *p || (*str > c && *str < *p))
|
||||
match = true;
|
||||
}
|
||||
else
|
||||
{ // c-]
|
||||
if (*str >= c)
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // cc or c]
|
||||
if (c == *str)
|
||||
match = true;
|
||||
if (*p != ']')
|
||||
{
|
||||
if (*p == *str)
|
||||
match = true;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (negate == match)
|
||||
return false;
|
||||
// if there is a match, skip past the cset and continue on
|
||||
while (*p && *p != ']')
|
||||
p++;
|
||||
if (!*p++) // oops!
|
||||
return false;
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
if (*p)
|
||||
c = *p++;
|
||||
default:
|
||||
if (c != *str)
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
str++;
|
||||
}
|
||||
|
||||
return !*str;
|
||||
}
|
||||
59
apps/elftosb/common/GlobMatcher.h
Normal file
59
apps/elftosb/common/GlobMatcher.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* File: GlobMatcher.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
#if !defined(_GlobMatcher_h_)
|
||||
#define _GlobMatcher_h_
|
||||
|
||||
#include "StringMatcher.h"
|
||||
|
||||
namespace elftosb
|
||||
{
|
||||
/*!
|
||||
* \brief This class uses glob pattern matching to match strings.
|
||||
*
|
||||
* Glob patterns:
|
||||
* - * matches zero or more characters
|
||||
* - ? matches any single character
|
||||
* - [set] matches any character in the set
|
||||
* - [^set] matches any character NOT in the set
|
||||
* where a set is a group of characters or ranges. a range
|
||||
* is written as two characters seperated with a hyphen: a-z denotes
|
||||
* all characters between a to z inclusive.
|
||||
* - [-set] set matches a literal hypen and any character in the set
|
||||
* - []set] matches a literal close bracket and any character in the set
|
||||
*
|
||||
* - char matches itself except where char is '*' or '?' or '['
|
||||
* - \\char matches char, including any pattern character
|
||||
*
|
||||
* Examples:
|
||||
* - a*c ac abc abbc ...
|
||||
* - a?c acc abc aXc ...
|
||||
* - a[a-z]c aac abc acc ...
|
||||
* - a[-a-z]c a-c aac abc ...
|
||||
*/
|
||||
class GlobMatcher : public StringMatcher
|
||||
{
|
||||
public:
|
||||
//! \brief Constructor.
|
||||
GlobMatcher(const std::string &pattern)
|
||||
: StringMatcher()
|
||||
, m_pattern(pattern)
|
||||
{
|
||||
}
|
||||
|
||||
//! \brief Returns whether \a testValue matches the glob pattern.
|
||||
virtual bool match(const std::string &testValue);
|
||||
|
||||
protected:
|
||||
std::string m_pattern; //!< The glob pattern to match against.
|
||||
|
||||
//! \brief Glob implementation.
|
||||
bool globMatch(const char *str, const char *p);
|
||||
};
|
||||
|
||||
}; // namespace elftosb
|
||||
|
||||
#endif // _GlobMatcher_h_
|
||||
34
apps/elftosb/common/HexValues.cpp
Normal file
34
apps/elftosb/common/HexValues.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* File: HexValues.cpp
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
|
||||
#include "HexValues.h"
|
||||
|
||||
bool isHexDigit(char c)
|
||||
{
|
||||
return isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
|
||||
}
|
||||
|
||||
//! \return The integer equivalent to \a c.
|
||||
//! \retval -1 The character \a c is not a hex character.
|
||||
uint8_t hexCharToInt(char c)
|
||||
{
|
||||
if (c >= '0' && c <= '9')
|
||||
return c - '0';
|
||||
else if (c >= 'a' && c <= 'f')
|
||||
return c - 'a' + 10;
|
||||
else if (c >= 'A' && c <= 'F')
|
||||
return c - 'A' + 10;
|
||||
else
|
||||
return static_cast<uint8_t>(-1);
|
||||
}
|
||||
|
||||
//! \param encodedByte Must point to at least two ASCII hex characters.
|
||||
//!
|
||||
uint8_t hexByteToInt(const char *encodedByte)
|
||||
{
|
||||
return (hexCharToInt(encodedByte[0]) << 4) | hexCharToInt(encodedByte[1]);
|
||||
}
|
||||
21
apps/elftosb/common/HexValues.h
Normal file
21
apps/elftosb/common/HexValues.h
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* File: HexValues.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
#if !defined(_HexValues_h_)
|
||||
#define _HexValues_h_
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
//! \brief Determines whether \a c is a hex digit character.
|
||||
bool isHexDigit(char c);
|
||||
|
||||
//! \brief Converts a hexidecimal character to the integer equivalent.
|
||||
uint8_t hexCharToInt(char c);
|
||||
|
||||
//! \brief Converts a hex-encoded byte to the integer equivalent.
|
||||
uint8_t hexByteToInt(const char *encodedByte);
|
||||
|
||||
#endif // _HexValues_h_
|
||||
111
apps/elftosb/common/IVTDataSource.cpp
Normal file
111
apps/elftosb/common/IVTDataSource.cpp
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* File: DataSource.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
*
|
||||
* Freescale Semiconductor, Inc.
|
||||
* Proprietary & Confidential
|
||||
*
|
||||
* This source code and the algorithms implemented therein constitute
|
||||
* confidential information and may comprise trade secrets of Freescale Semiconductor, Inc.
|
||||
* or its associates, and any use thereof is subject to the terms and
|
||||
* conditions of the Confidential Disclosure Agreement pursual to which this
|
||||
* source code was originally received.
|
||||
*/
|
||||
|
||||
#include "IVTDataSource.h"
|
||||
#include "DataTarget.h"
|
||||
#include "EndianUtilities.h"
|
||||
#include <algorithm>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
using namespace elftosb;
|
||||
|
||||
IVTDataSource::IVTDataSource()
|
||||
: DataSource()
|
||||
, DataSource::Segment((DataSource &)*this)
|
||||
, m_isSelfSet(false)
|
||||
{
|
||||
// Init the IVT structure.
|
||||
memset(&m_ivt, 0, sizeof(m_ivt));
|
||||
hab_hdr_t hdr = IVT_HDR(sizeof(m_ivt), HAB_VERSION);
|
||||
m_ivt.hdr = hdr;
|
||||
}
|
||||
|
||||
unsigned IVTDataSource::getData(unsigned offset, unsigned maxBytes, uint8_t *buffer)
|
||||
{
|
||||
// Bail if the offset is out of range.
|
||||
if (offset >= sizeof(m_ivt))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If we have an associated target, and the IVT self pointer is not set, then
|
||||
// fill in the self pointer from the target address.
|
||||
if (m_target && !m_isSelfSet)
|
||||
{
|
||||
m_ivt.self = ENDIAN_HOST_TO_LITTLE_U32(m_target->getBeginAddress());
|
||||
}
|
||||
|
||||
// Truncate max bytes at the end of the IVT.
|
||||
maxBytes = std::min<unsigned>(maxBytes, sizeof(m_ivt) - offset);
|
||||
|
||||
// Copy into output buffer.
|
||||
if (maxBytes)
|
||||
{
|
||||
memcpy(buffer, (uint8_t *)&m_ivt + offset, maxBytes);
|
||||
}
|
||||
|
||||
return maxBytes;
|
||||
}
|
||||
|
||||
unsigned IVTDataSource::getLength()
|
||||
{
|
||||
return sizeof(m_ivt);
|
||||
}
|
||||
|
||||
//! The IVT has a natural location if its self pointer was explicitly specified.
|
||||
//!
|
||||
bool IVTDataSource::hasNaturalLocation()
|
||||
{
|
||||
return m_isSelfSet;
|
||||
}
|
||||
|
||||
//!
|
||||
uint32_t IVTDataSource::getBaseAddress()
|
||||
{
|
||||
return m_ivt.self;
|
||||
}
|
||||
|
||||
bool IVTDataSource::setFieldByName(const std::string &name, uint32_t value)
|
||||
{
|
||||
if (name == "entry")
|
||||
{
|
||||
m_ivt.entry = ENDIAN_HOST_TO_LITTLE_U32(value);
|
||||
}
|
||||
else if (name == "dcd")
|
||||
{
|
||||
m_ivt.dcd = ENDIAN_HOST_TO_LITTLE_U32(value);
|
||||
}
|
||||
else if (name == "boot_data")
|
||||
{
|
||||
m_ivt.boot_data = ENDIAN_HOST_TO_LITTLE_U32(value);
|
||||
}
|
||||
else if (name == "self")
|
||||
{
|
||||
m_ivt.self = ENDIAN_HOST_TO_LITTLE_U32(value);
|
||||
m_isSelfSet = true;
|
||||
}
|
||||
else if (name == "csf")
|
||||
{
|
||||
m_ivt.csf = ENDIAN_HOST_TO_LITTLE_U32(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unrecognized field name.
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
285
apps/elftosb/common/IVTDataSource.h
Normal file
285
apps/elftosb/common/IVTDataSource.h
Normal file
@@ -0,0 +1,285 @@
|
||||
/*
|
||||
* File: DataSource.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
*
|
||||
* Freescale Semiconductor, Inc.
|
||||
* Proprietary & Confidential
|
||||
*
|
||||
* This source code and the algorithms implemented therein constitute
|
||||
* confidential information and may comprise trade secrets of Freescale Semiconductor, Inc.
|
||||
* or its associates, and any use thereof is subject to the terms and
|
||||
* conditions of the Confidential Disclosure Agreement pursual to which this
|
||||
* source code was originally received.
|
||||
*/
|
||||
#if !defined(_IVTDataSource_h_)
|
||||
#define _IVTDataSource_h_
|
||||
|
||||
#include "DataSource.h"
|
||||
|
||||
/** Header field components
|
||||
* @ingroup hdr
|
||||
*/
|
||||
typedef struct hab_hdr
|
||||
{
|
||||
uint8_t tag; /**< Tag field */
|
||||
uint8_t len[2]; /**< Length field in bytes (big-endian) */
|
||||
uint8_t par; /**< Parameters field */
|
||||
} hab_hdr_t;
|
||||
|
||||
/** Image entry function prototype
|
||||
* @ingroup rvt
|
||||
*
|
||||
* This typedef serves as the return type for hab_rvt.authenticate_image(). It
|
||||
* specifies a void-void function pointer, but can be cast to another function
|
||||
* pointer type if required.
|
||||
*/
|
||||
typedef void (*hab_image_entry_f)(void);
|
||||
|
||||
/** @ref ivt structure
|
||||
* @ingroup ivt
|
||||
*
|
||||
* @par Format
|
||||
*
|
||||
* An @ref ivt consists of a @ref hdr followed by a list of addresses as
|
||||
* described further below.
|
||||
*
|
||||
* @warning The @a entry address may not be NULL.
|
||||
*
|
||||
* @warning On an IC not configured as #HAB_CFG_CLOSED, the
|
||||
* @a csf address may be NULL. If it is not NULL, the @ref csf will be
|
||||
* processed, but any failures should be non-fatal.
|
||||
*
|
||||
* @warning On an IC configured as #HAB_CFG_CLOSED, the @a
|
||||
* csf address may not be NULL, and @ref csf failures are typically fatal.
|
||||
*
|
||||
* @remark The Boot Data located using the @a boot_data field is interpreted
|
||||
* by the HAB caller in a boot-mode specific manner. This may be used by the
|
||||
* boot ROM as to determine the load address and boot device configuration for
|
||||
* images loaded from block devices (see @ref ref_rug for details).
|
||||
*
|
||||
* @remark All addresses given in the IVT, including the Boot Data (if
|
||||
* present) are those for the final load location.
|
||||
*
|
||||
* @anchor ila
|
||||
*
|
||||
* @par Initial load addresses
|
||||
*
|
||||
* The @a self field is used to calculate addresses in boot modes where an
|
||||
* initial portion of the image is loaded to an initial location. In such
|
||||
* cases, the IVT, Boot Data (if present) and DCD (if present) are used in
|
||||
* configuring the IC and loading the full image to its final location. Only
|
||||
* the IVT, Boot Data (if present) and DCD (if present) are required to be
|
||||
* within the initial image portion.
|
||||
*
|
||||
* The method for calculating an initial load address for the DCD is
|
||||
* illustrated in the following C fragment. Similar calculations apply to
|
||||
* other fields.
|
||||
*
|
||||
@verbatim
|
||||
hab_ivt_t* ivt_initial = <initial IVT load address>;
|
||||
const void* dcd_initial = ivt_initial->dcd;
|
||||
if (ivt_initial->dcd != NULL)
|
||||
dcd_initial = (const uint8_t*)ivt_initial
|
||||
+ (ivt_initial->dcd - ivt_initial->self)
|
||||
@endverbatim
|
||||
|
||||
* \note The void* types in this structure have been changed to uint32_t so
|
||||
* that this code will work correctly when compiled on a 64-bit host.
|
||||
* Otherwise the structure would come out incorrect.
|
||||
*/
|
||||
struct hab_ivt
|
||||
{
|
||||
/** @ref hdr with tag #HAB_TAG_IVT, length and HAB version fields
|
||||
* (see @ref data)
|
||||
*/
|
||||
hab_hdr_t hdr;
|
||||
/** Absolute address of the first instruction to execute from the
|
||||
* image
|
||||
*/
|
||||
/*hab_image_entry_f*/ uint32_t entry;
|
||||
/** Reserved in this version of HAB: should be NULL. */
|
||||
/*const void*/ uint32_t reserved1;
|
||||
/** Absolute address of the image DCD: may be NULL. */
|
||||
/*const void*/ uint32_t dcd;
|
||||
/** Absolute address of the Boot Data: may be NULL, but not interpreted
|
||||
* any further by HAB
|
||||
*/
|
||||
/*const void*/ uint32_t boot_data;
|
||||
/** Absolute address of the IVT.*/
|
||||
/*const void*/ uint32_t self;
|
||||
/** Absolute address of the image CSF.*/
|
||||
/*const void*/ uint32_t csf;
|
||||
/** Reserved in this version of HAB: should be zero. */
|
||||
uint32_t reserved2;
|
||||
};
|
||||
|
||||
/** @ref ivt type
|
||||
* @ingroup ivt
|
||||
*/
|
||||
typedef struct hab_ivt hab_ivt_t;
|
||||
|
||||
/*
|
||||
* Helper macros
|
||||
*/
|
||||
#define HAB_CMD_UNS 0xff
|
||||
|
||||
#define DEFAULT_IMG_KEY_IDX 2
|
||||
|
||||
#define GEN_MASK(width) ((1UL << (width)) - 1)
|
||||
|
||||
#define GEN_FIELD(f, width, shift) (((f)&GEN_MASK(width)) << (shift))
|
||||
|
||||
#define PACK_UINT32(a, b, c, d) ((((a)&0xFF) << 24) | (((b)&0xFF) << 16) | (((c)&0xFF) << 8) | (((d)&0xFF)))
|
||||
|
||||
#define EXPAND_UINT32(w) (uint8_t)((w) >> 24), (uint8_t)((w) >> 16), (uint8_t)((w) >> 8), (uint8_t)(w)
|
||||
|
||||
#define HDR(tag, bytes, par) (uint8_t)(tag), (uint8_t)((bytes) >> 8), (uint8_t)(bytes), (uint8_t)(par)
|
||||
|
||||
#define HAB_VER(maj, min) \
|
||||
(GEN_FIELD((maj), HAB_VER_MAJ_WIDTH, HAB_VER_MAJ_SHIFT) | GEN_FIELD((min), HAB_VER_MIN_WIDTH, HAB_VER_MIN_SHIFT))
|
||||
|
||||
/*
|
||||
* CSF header
|
||||
*/
|
||||
|
||||
#define CSF_HDR(bytes, HABVER) HDR(HAB_TAG_CSF, (bytes), HABVER)
|
||||
|
||||
/*
|
||||
* DCD header
|
||||
*/
|
||||
|
||||
#define DCD_HDR(bytes, HABVER) HDR(HAB_TAG_DCD, (bytes), HABVER)
|
||||
|
||||
/*
|
||||
* IVT header (goes in the struct's hab_hdr_t field, not a byte array)
|
||||
*/
|
||||
#define IVT_HDR(bytes, HABVER) \
|
||||
{ \
|
||||
HAB_TAG_IVT, { (uint8_t)((bytes) >> 8), (uint8_t)(bytes) }, HABVER \
|
||||
}
|
||||
|
||||
/** @name External data structure tags
|
||||
* @anchor dat_tag
|
||||
*
|
||||
* Tag values 0x00 .. 0xef are reserved for HAB. Values 0xf0 .. 0xff
|
||||
* are available for custom use.
|
||||
*/
|
||||
/*@{*/
|
||||
#define HAB_TAG_IVT 0xd1 /**< Image Vector Table */
|
||||
#define HAB_TAG_DCD 0xd2 /**< Device Configuration Data */
|
||||
#define HAB_TAG_CSF 0xd4 /**< Command Sequence File */
|
||||
#define HAB_TAG_CRT 0xd7 /**< Certificate */
|
||||
#define HAB_TAG_SIG 0xd8 /**< Signature */
|
||||
#define HAB_TAG_EVT 0xdb /**< Event */
|
||||
#define HAB_TAG_RVT 0xdd /**< ROM Vector Table */
|
||||
/* Values b0 ... cf reserved for CSF commands. Values e0 ... ef reserved for
|
||||
* key types.
|
||||
*
|
||||
* Available values: 03, 05, 06, 09, 0a, 0c, 0f, 11, 12, 14, 17, 18, 1b, 1d,
|
||||
* 1e, 21, 22, 24, 27, 28, 2b, 2d, 2e, 30, 33, 35, 36, 39, 3a, 3c, 3f, 41, 42,
|
||||
* 44, 47, 48, 4b, 4d, 4e, 50, 53, 55, 56, 59, 5a, 5c, 5f, 60, 63, 65, 66, 69,
|
||||
* 6a, 6c, 6f, 71, 72, 74, 77, 78, 7b, 7d, 7e, 81, 82, 84, 87, 88, 8b, 8d, 8e,
|
||||
* 90, 93, 95, 96, 99, 9a, 9c, 9f, a0, a3, a5, a6, a9, aa, ac, af, b1, b2, b4,
|
||||
* b7, b8, bb, bd, be
|
||||
*
|
||||
* Custom values: f0, f3, f5, f6, f9, fa, fc, ff
|
||||
*/
|
||||
/*@}*/
|
||||
|
||||
/** @name HAB version */
|
||||
/*@{*/
|
||||
#define HAB_MAJOR_VERSION 4 /**< Major version of this HAB release */
|
||||
#define HAB_MINOR_VERSION 0 /**< Minor version of this HAB release */
|
||||
#define HAB_VER_MAJ_WIDTH 4 /**< Major version field width */
|
||||
#define HAB_VER_MAJ_SHIFT 4 /**< Major version field offset */
|
||||
#define HAB_VER_MIN_WIDTH 4 /**< Minor version field width */
|
||||
#define HAB_VER_MIN_SHIFT 0 /**< Minor version field offset */
|
||||
/** Full version of this HAB release @hideinitializer */
|
||||
#define HAB_VERSION HAB_VER(HAB_MAJOR_VERSION, HAB_MINOR_VERSION)
|
||||
/** Base version for this HAB release @hideinitializer */
|
||||
#define HAB_BASE_VERSION HAB_VER(HAB_MAJOR_VERSION, 0)
|
||||
|
||||
/*@}*/
|
||||
|
||||
namespace elftosb
|
||||
{
|
||||
/*!
|
||||
* \brief Data source for an IVT structure used by HAB4.
|
||||
*
|
||||
* This data source represents an IVT structure used by HAB4. Fields of the IVT can be set
|
||||
* by name, making it easy to interface with a parser. And it has some intelligence regarding
|
||||
* the IVT's self pointer. Before the data is copied out by the getData() method, the self field
|
||||
* will be filled in automatically if it has not already been set and there is an associated
|
||||
* data target object. This lets the IVT pick up its own address from the location where it is
|
||||
* being loaded. Alternatively, if the self pointer is filled in explicitly, then the data
|
||||
* source will have a natural location equal to the self pointer.
|
||||
*
|
||||
* This data source acts as its own segment.
|
||||
*/
|
||||
class IVTDataSource : public DataSource, public DataSource::Segment
|
||||
{
|
||||
public:
|
||||
//! \brief Default constructor.
|
||||
IVTDataSource();
|
||||
|
||||
//! \brief There is only one segment.
|
||||
virtual unsigned getSegmentCount() { return 1; }
|
||||
//! \brief Returns this object, as it is its own segment.
|
||||
virtual DataSource::Segment *getSegmentAt(unsigned index) { return this; }
|
||||
//! \name Segment methods
|
||||
//@{
|
||||
|
||||
//! \brief Copy out some or all of the IVT structure.
|
||||
//!
|
||||
virtual unsigned getData(unsigned offset, unsigned maxBytes, uint8_t *buffer);
|
||||
|
||||
//! \brief Gets the length of the segment's data.
|
||||
virtual unsigned getLength();
|
||||
|
||||
//! \brief Returns whether the segment has an associated address.
|
||||
virtual bool hasNaturalLocation();
|
||||
|
||||
//! \brief Returns the address associated with the segment.
|
||||
virtual uint32_t getBaseAddress();
|
||||
|
||||
//@}
|
||||
|
||||
//! \name IVT access
|
||||
//@{
|
||||
|
||||
//! \brief Set one of the IVT's fields by providing its name.
|
||||
//!
|
||||
//! Acceptable field names are:
|
||||
//! - entry
|
||||
//! - dcd
|
||||
//! - boot_data
|
||||
//! - self
|
||||
//! - csf
|
||||
//!
|
||||
//! As long as the \a name parameter specifies one of these fields, the return value
|
||||
//! will be true. If \a name contains any other value, then false will be returned and
|
||||
//! the IVT left unmodified.
|
||||
//!
|
||||
//! Once the \a self field has been set to any value, the data source will have a
|
||||
//! natural location. This works even if the \a self address is 0.
|
||||
//!
|
||||
//! \param name The name of the field to set. Field names are case sensitive, just like in
|
||||
//! the C language.
|
||||
//! \param value The value to which the field will be set.
|
||||
//! \retval true The field was set successfully.
|
||||
//! \retval false There is no field with the provided name.
|
||||
bool setFieldByName(const std::string &name, uint32_t value);
|
||||
|
||||
//! \brief Returns a reference to the IVT structure.
|
||||
hab_ivt_t &getIVT() { return m_ivt; }
|
||||
//@}
|
||||
|
||||
protected:
|
||||
hab_ivt_t m_ivt; //!< The IVT structure.
|
||||
bool m_isSelfSet; //!< True if the IVT self pointer was explicitly set.
|
||||
};
|
||||
|
||||
} // elftosb
|
||||
|
||||
#endif // _IVTDataSource_h_
|
||||
376
apps/elftosb/common/Keyblob.cpp
Normal file
376
apps/elftosb/common/Keyblob.cpp
Normal file
@@ -0,0 +1,376 @@
|
||||
/*
|
||||
* File: Keyblob.cpp
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#if WIN32
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include "Keyblob.h"
|
||||
#include "Logging.h"
|
||||
#include "aes128_key_wrap_unwrap.h"
|
||||
#include "crc.h"
|
||||
#include "RijndaelCTR.h"
|
||||
|
||||
#define PRINT_KEYBLOB 0
|
||||
#define DEBUG_DATA 0
|
||||
|
||||
// From bytes_aes.c.
|
||||
extern "C" void KeyExpansion(unsigned char ckey[], int nbits, unsigned int w[]);
|
||||
|
||||
using namespace elftosb;
|
||||
|
||||
void Keyblob::encrypt(uint32_t length, uint8_t *data, AESKey<128> *key, AESCounter<128> *counter)
|
||||
{
|
||||
// Create counter mode encrypter.
|
||||
RijndaelCTR encrypter(*key, *counter);
|
||||
|
||||
uint32_t tempBlock[k_encryptBlockSize / sizeof(uint32_t)];
|
||||
uint32_t bytesEncrypted = 0;
|
||||
const uint32_t blockSize = k_encryptBlockSize;
|
||||
|
||||
// length must be a multiple of k_blockSize and k_qspiAlignlength.
|
||||
assert(length && !(length % blockSize) && !(length % k_qspiAlignlength));
|
||||
|
||||
// Encrypt all blocks of data from the image.
|
||||
while (bytesEncrypted < length)
|
||||
{
|
||||
memset(tempBlock, 0, sizeof(tempBlock));
|
||||
|
||||
// Copy in plaintext data.
|
||||
memcpy(tempBlock, data, blockSize);
|
||||
|
||||
// We endian swap each uint32_t in the block and then swap word 0 <-> word 1 and word 2 <-> word 3
|
||||
// to counter for endian issues and 64 bit writes on the device with a QSPI configuration for 64 bit LE
|
||||
// this lets unencrypted byte streams as well as this encrypted byte stream be transparently used by the driver
|
||||
#if WIN32
|
||||
tempBlock[0] = _byteswap_ulong(tempBlock[0]);
|
||||
tempBlock[1] = _byteswap_ulong(tempBlock[1]);
|
||||
tempBlock[2] = _byteswap_ulong(tempBlock[2]);
|
||||
tempBlock[3] = _byteswap_ulong(tempBlock[3]);
|
||||
#else
|
||||
tempBlock[0] = __builtin_bswap32(tempBlock[0]);
|
||||
tempBlock[1] = __builtin_bswap32(tempBlock[1]);
|
||||
tempBlock[2] = __builtin_bswap32(tempBlock[2]);
|
||||
tempBlock[3] = __builtin_bswap32(tempBlock[3]);
|
||||
#endif
|
||||
|
||||
std::swap(tempBlock[0], tempBlock[1]);
|
||||
std::swap(tempBlock[2], tempBlock[3]);
|
||||
|
||||
encrypter.encrypt((uint8_t *)tempBlock, sizeof(tempBlock), (uint8_t *)tempBlock);
|
||||
|
||||
// Reverse the above transform so that it is back in its original order when decrypted
|
||||
std::swap(tempBlock[0], tempBlock[1]);
|
||||
std::swap(tempBlock[2], tempBlock[3]);
|
||||
|
||||
#if WIN32
|
||||
tempBlock[0] = _byteswap_ulong(tempBlock[0]);
|
||||
tempBlock[1] = _byteswap_ulong(tempBlock[1]);
|
||||
tempBlock[2] = _byteswap_ulong(tempBlock[2]);
|
||||
tempBlock[3] = _byteswap_ulong(tempBlock[3]);
|
||||
#else
|
||||
tempBlock[0] = __builtin_bswap32(tempBlock[0]);
|
||||
tempBlock[1] = __builtin_bswap32(tempBlock[1]);
|
||||
tempBlock[2] = __builtin_bswap32(tempBlock[2]);
|
||||
tempBlock[3] = __builtin_bswap32(tempBlock[3]);
|
||||
#endif
|
||||
|
||||
// Overwrite plaintext data with enrypted data.
|
||||
std::memcpy(data, tempBlock, blockSize);
|
||||
|
||||
bytesEncrypted += blockSize;
|
||||
data += blockSize;
|
||||
}
|
||||
}
|
||||
|
||||
AESCounter<128> *buildCounter(const std::string &counterVal, uint32_t startAddress)
|
||||
{
|
||||
/* CTRn_x[127-0] = {CTR_W0_x[C0...C3], // 32 bits of pre-programmed CTR
|
||||
CTR_W1_x[C4...C7], // another 32 bits of CTR
|
||||
CTR_W0_x[C0...C3] ^ CTR_W1_x[C4...C7], // exclusive-OR of CTR values
|
||||
systemAddress[31-4], 0000b} // 0-modulo-16 system address */
|
||||
|
||||
assert(counterVal.size() == 16); // We need 16 characters for the counter value
|
||||
assert(!(startAddress % 16)); // Start adress has to be 16 byte aligned
|
||||
|
||||
AESCounter<128>::counter_t counter;
|
||||
std::string counterW0String = counterVal.substr(0, 8);
|
||||
std::string counterW1String = counterVal.substr(8, 8);
|
||||
uint32_t counterW0 = strtoul(counterW0String.c_str(), NULL, 16);
|
||||
uint32_t counterW1 = strtoul(counterW1String.c_str(), NULL, 16);
|
||||
uint32_t counterXOR = counterW0 ^ counterW1;
|
||||
|
||||
// Form the collected data into a 16 byte array
|
||||
counter[15] = startAddress & 0xFF;
|
||||
counter[14] = (startAddress & 0xFF00) >> 8;
|
||||
counter[13] = static_cast<uint8_t>((startAddress & 0xFF0000) >> 16);
|
||||
counter[12] = (startAddress & 0xFF000000) >> 24;
|
||||
|
||||
counter[11] = counterXOR & 0xFF;
|
||||
counter[10] = (counterXOR & 0xFF00) >> 8;
|
||||
counter[9] = static_cast<uint8_t>((counterXOR & 0xFF0000) >> 16);
|
||||
counter[8] = (counterXOR & 0xFF000000) >> 24;
|
||||
|
||||
counter[7] = counterW1 & 0xFF;
|
||||
counter[6] = (counterW1 & 0xFF00) >> 8;
|
||||
counter[5] = static_cast<uint8_t>((counterW1 & 0xFF0000) >> 16);
|
||||
counter[4] = (counterW1 & 0xFF000000) >> 24;
|
||||
|
||||
counter[3] = counterW0 & 0xFF;
|
||||
counter[2] = (counterW0 & 0xFF00) >> 8;
|
||||
counter[1] = static_cast<uint8_t>((counterW0 & 0xFF0000) >> 16);
|
||||
counter[0] = (counterW0 & 0xFF000000) >> 24;
|
||||
|
||||
return new AESCounter<128>(counter); // caller must deallocate
|
||||
}
|
||||
|
||||
bool Keyblob::encryptMatchingRange(uint32_t start, uint32_t len, uint8_t *data)
|
||||
{
|
||||
assert(data);
|
||||
option_vector_t *options = getOptions();
|
||||
unsigned matchedCount = 0;
|
||||
#if DEBUG_DATA
|
||||
std::ofstream qspiBin("enc.bin", std::ios_base::binary | std::ios_base::out | std::ios_base::trunc);
|
||||
#endif
|
||||
|
||||
// Go through each option entry to find matching range.
|
||||
// Encrypt the data in place.
|
||||
option_vector_t::iterator it = options->begin();
|
||||
for (; it != options->end(); ++it)
|
||||
{
|
||||
uint32_t entryStart = 0;
|
||||
uint32_t entryEnd = 0;
|
||||
const char *keyHex = NULL;
|
||||
const char *counterHex = NULL;
|
||||
|
||||
// Ignore entry if not all options are present.
|
||||
if (!getOptionValues(**it, &keyHex, &counterHex, &entryStart, &entryEnd))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Start address must exactly match region address.
|
||||
// Region addersses are already forced to modulo 1024.
|
||||
if (entryStart == start)
|
||||
{
|
||||
// Build counter value.
|
||||
std::string counterStr(counterHex);
|
||||
AESCounter<128> *counter = buildCounter(counterStr, start);
|
||||
|
||||
// Build key value.
|
||||
AESKey<128> key;
|
||||
std::stringstream infoStream;
|
||||
infoStream << keyHex;
|
||||
key.readFromStream(infoStream);
|
||||
|
||||
Log::log(Logger::INFO2, "creating encrypted range 0x%x len 0x%x\n", start, len);
|
||||
++matchedCount;
|
||||
|
||||
encrypt(len, data, &key, counter);
|
||||
#if DEBUG_DATA
|
||||
qspiBin.write(reinterpret_cast<char *>(data), 0x400);
|
||||
#endif
|
||||
|
||||
delete counter;
|
||||
break; // only one entry is processed per base address
|
||||
}
|
||||
}
|
||||
|
||||
return (matchedCount > 0);
|
||||
}
|
||||
|
||||
void hexToBytes(const char *hexStr, unsigned char *bytes, int numBytes)
|
||||
{
|
||||
for (int i = 0; i < numBytes; ++i)
|
||||
{
|
||||
char digitBuf[3];
|
||||
digitBuf[0] = *hexStr++;
|
||||
digitBuf[1] = *hexStr++;
|
||||
digitBuf[2] = '\0';
|
||||
|
||||
bytes[i] = (unsigned char)strtoul(digitBuf, NULL, 16);
|
||||
}
|
||||
}
|
||||
|
||||
void Keyblob::populateKeyBlob(keyblob_t *blob, uint32_t start, uint32_t end, const char *keyHex, const char *counterHex)
|
||||
{
|
||||
// Populate key value.
|
||||
hexToBytes(keyHex, blob->key, sizeof(blob->key));
|
||||
|
||||
// Poplulate Counter value.
|
||||
hexToBytes(counterHex, blob->ctr, sizeof(blob->ctr));
|
||||
|
||||
blob->srtaddr = start & ~kRegionAddrMask;
|
||||
blob->endaddr = end | kRegionAddrMask;
|
||||
// Add default flags to endaddr register.
|
||||
blob->endaddr &= ~kFlagMask;
|
||||
blob->endaddr |= kKeyFlags;
|
||||
|
||||
// Add CRC32.
|
||||
uint32_t result;
|
||||
CRC32 crc;
|
||||
crc.update(reinterpret_cast<uint8_t *>(blob), kCrc32SizeBytes);
|
||||
crc.truncatedFinal(reinterpret_cast<uint8_t *>(&result), sizeof(result));
|
||||
blob->key_blob_crc32 = result;
|
||||
}
|
||||
|
||||
uint8_t *Keyblob::createWrappedKeyblobData(uint8_t *kek, uint32_t *byteCount)
|
||||
{
|
||||
assert(kek);
|
||||
assert(byteCount);
|
||||
|
||||
option_vector_t *options = getOptions();
|
||||
uint32_t entryCount = options->size();
|
||||
uint8_t *unwrappedData = new uint8_t[entryCount * sizeof(keyblob_t)];
|
||||
keyblob_t *blob = (keyblob_t *)&unwrappedData[0];
|
||||
uint8_t *wrappedData = new uint8_t[entryCount * sizeof(keyblob_t)];
|
||||
uint8_t *wrapped = wrappedData;
|
||||
|
||||
// Create expanded KeK for AES128 encryption.
|
||||
unsigned int *expandedKek = new unsigned int[kExpandedKekSizeInts];
|
||||
KeyExpansion(reinterpret_cast<unsigned char *>(&kek[0]), kKeySizeBits, expandedKek);
|
||||
|
||||
option_vector_t::iterator it = options->begin();
|
||||
for (; it != options->end(); ++it)
|
||||
{
|
||||
uint32_t start = 0;
|
||||
uint32_t end = 0;
|
||||
const char *keyHex = NULL;
|
||||
const char *counterHex = NULL;
|
||||
|
||||
// If not all options are present, make it a null entry.
|
||||
bool isValidEntry = getOptionValues(**it, &keyHex, &counterHex, &start, &end);
|
||||
|
||||
// Clear this wrapped entry.
|
||||
memset(wrapped, 0, kKeyBlobSizeBytes);
|
||||
|
||||
if (isValidEntry)
|
||||
{
|
||||
// Fill in keyblob data.
|
||||
memset(blob, 0, sizeof(keyblob_t));
|
||||
populateKeyBlob(blob, start, end, keyHex, counterHex);
|
||||
|
||||
#if PRINT_KEYBLOB
|
||||
uint8_t *keyData = reinterpret_cast<uint8_t *>(blob);
|
||||
Log::log(" ;plaintext\n");
|
||||
for (int i = 0; i < kKeyBlobSizeBytes / kOutputLineSize; ++i)
|
||||
{
|
||||
Log::log(" ; ");
|
||||
for (int j = 0; j < kOutputLineSize - 1; ++j)
|
||||
{
|
||||
Log::log("0x%02x, ", *keyData++);
|
||||
}
|
||||
Log::log("0x%02x\n", *keyData++);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Wrap keyblob entry.
|
||||
do_aes128_key_wrap(reinterpret_cast<uint8_t *>(blob), wrapped, expandedKek);
|
||||
|
||||
#if PRINT_KEYBLOB
|
||||
keyData = wrapped;
|
||||
Log::log(" ;wrapped\n");
|
||||
for (int i = 0; i < kKeyBlobSizeBytes / kOutputLineSize; ++i)
|
||||
{
|
||||
printf(" DC8 ");
|
||||
for (int j = 0; j < kOutputLineSize - 1; ++j)
|
||||
{
|
||||
printf("0x%02x, ", *keyData++);
|
||||
}
|
||||
printf("0x%02x\n", *keyData++);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Next unwrapped and wrapped keyblob data pointers.
|
||||
++blob;
|
||||
wrapped += sizeof(keyblob_t);
|
||||
}
|
||||
|
||||
delete[] expandedKek;
|
||||
delete[] unwrappedData;
|
||||
|
||||
*byteCount = entryCount * sizeof(keyblob_t);
|
||||
return wrappedData; // must be deleted by caller
|
||||
}
|
||||
|
||||
bool Keyblob::getOptionValues(OptionContext &opt, const char **key, const char **ctr, uint32_t *start, uint32_t *end)
|
||||
{
|
||||
assert(key && ctr && start && end);
|
||||
|
||||
if (!(opt.hasOption(kKeyblobOptionNameStart) && opt.hasOption(kKeyblobOptionNameEnd) &&
|
||||
opt.hasOption(kKeyblobOptionNameKey) && opt.hasOption(kKeyblobOptionNameCounter)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (opt.hasOption(kKeyblobOptionNameStart))
|
||||
{
|
||||
const Value *value = opt.getOption(kKeyblobOptionNameStart);
|
||||
const IntegerValue *intValue = dynamic_cast<const IntegerValue *>(value);
|
||||
if (!intValue)
|
||||
{
|
||||
Log::log(Logger::WARNING, "invalid type for %s option\n", kKeyblobOptionNameStart);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
*start = intValue->getValue();
|
||||
}
|
||||
}
|
||||
|
||||
if (opt.hasOption(kKeyblobOptionNameEnd))
|
||||
{
|
||||
const Value *value = opt.getOption(kKeyblobOptionNameEnd);
|
||||
const IntegerValue *intValue = dynamic_cast<const IntegerValue *>(value);
|
||||
if (!intValue)
|
||||
{
|
||||
Log::log(Logger::WARNING, "invalid type for %s option\n", kKeyblobOptionNameEnd);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
*end = intValue->getValue();
|
||||
}
|
||||
}
|
||||
|
||||
if (opt.hasOption(kKeyblobOptionNameKey))
|
||||
{
|
||||
const Value *value = opt.getOption(kKeyblobOptionNameKey);
|
||||
const StringValue *stringValue = dynamic_cast<const StringValue *>(value);
|
||||
if (!stringValue)
|
||||
{
|
||||
Log::log(Logger::WARNING, "invalid type for %s option\n", kKeyblobOptionNameKey);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
*key = *stringValue;
|
||||
}
|
||||
}
|
||||
|
||||
if (opt.hasOption(kKeyblobOptionNameCounter))
|
||||
{
|
||||
const Value *value = opt.getOption(kKeyblobOptionNameCounter);
|
||||
const StringValue *stringValue = dynamic_cast<const StringValue *>(value);
|
||||
if (!stringValue)
|
||||
{
|
||||
Log::log(Logger::WARNING, "invalid type for %s option\n", kKeyblobOptionNameCounter);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
*ctr = *stringValue;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
120
apps/elftosb/common/Keyblob.h
Normal file
120
apps/elftosb/common/Keyblob.h
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* File: Keyblob.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
#if !defined(_Keyblob_h_)
|
||||
#define _Keyblob_h_
|
||||
|
||||
#include "smart_ptr.h"
|
||||
#include "OptionContext.h"
|
||||
#include "DataTarget.h"
|
||||
#include "AESKey.h"
|
||||
#include "AESCounter.h"
|
||||
|
||||
//! The names of the options.
|
||||
#define kKeyblobOptionNameStart "start"
|
||||
#define kKeyblobOptionNameEnd "end"
|
||||
#define kKeyblobOptionNameKey "key"
|
||||
#define kKeyblobOptionNameCounter "counter"
|
||||
|
||||
namespace elftosb
|
||||
{
|
||||
/*!
|
||||
* @brief Keyblob specification.
|
||||
*/
|
||||
class Keyblob
|
||||
{
|
||||
public:
|
||||
typedef std::vector<OptionContext *> option_vector_t; //!< List of options entries.
|
||||
|
||||
//! @brief Constants for encryption.
|
||||
enum _encryption_constants
|
||||
{
|
||||
k_encryptBlockSize = 16, //!< Block size for AES-128 encryption
|
||||
k_qspiAlignlength =
|
||||
512 //!< QSPI image alignment length, 512 is supposed to be the safe alignment level for any QSPI device
|
||||
//!< this means that all QSPI images generated by this tool will be sizes of multiple 512
|
||||
};
|
||||
|
||||
public:
|
||||
Keyblob()
|
||||
: m_id(0)
|
||||
, m_options(0)
|
||||
{
|
||||
}
|
||||
Keyblob(uint32_t identifier)
|
||||
: m_id(identifier)
|
||||
, m_options(0)
|
||||
{
|
||||
}
|
||||
virtual ~Keyblob() {}
|
||||
static uint32_t getKekSizeBytes() { return kKekSizeBytes; }
|
||||
void setIdentifier(uint32_t identifier) { m_id = identifier; }
|
||||
uint32_t getIdentifier() const { return m_id; }
|
||||
//! \brief Add options.
|
||||
inline void addOptions(OptionContext *context) { m_options.push_back(context); }
|
||||
//! \brief Return options vector.
|
||||
inline option_vector_t *getOptions() { return &m_options; }
|
||||
//! \brief Create and wrap keyblob data based on options.
|
||||
//!
|
||||
//! \retval Pointer to new wrapped data (caller must delete)
|
||||
//! \retval Number of bytes in wrapped data
|
||||
uint8_t *createWrappedKeyblobData(uint8_t *kek, uint32_t *byteCount);
|
||||
|
||||
//! \brief Encrypt for OTFAD if range is within a keyblob entry range.
|
||||
//!
|
||||
//! len must be a multiple of k_qspiAlignlength, which is also
|
||||
//! a multiple of k_encryptBlockSize.
|
||||
//!
|
||||
//! \retval True if data was encrypted (range matched)
|
||||
bool encryptMatchingRange(uint32_t start, uint32_t len, uint8_t *data);
|
||||
|
||||
protected:
|
||||
//! @brief Keywrap constants.
|
||||
enum _keywrap_constants
|
||||
{
|
||||
kKeySizeBits = 128, //!< AES-128
|
||||
kExpandedKekSizeInts = 64, //!< Expanded KeK size
|
||||
kNumKeyBlobs = 4, //!< Number of key blobs
|
||||
kKeyBlobSizeBytes = 64, //!< Key blob size in bytes
|
||||
kOutputLineSize = 16, //!< Number of bytes per output line
|
||||
kRegionAddrMask = (0x400 - 1), //!< Region addresses are modulo 1024
|
||||
kFlagMask = 0x07, //!< Key flags mask
|
||||
kKeyFlags = 0x03, //!< Default flags: RO=0, ADE=1, VLD=1
|
||||
kAesKeySizeBytes = 16, //!< Number of bytes in AES-128 key
|
||||
kCtrSizeBytes = 8, //!< Number of bytes in Ctr
|
||||
kKekSizeBytes = 16, //!< Number of bytes in KeK
|
||||
kNumKeyChars = 32, //!< Number of characters in key string
|
||||
kNumCtrChars = 16, //!< Number of characters in ctr string
|
||||
kCrc32SizeBytes = 32 //!< Number of bytes covered by CRC32
|
||||
};
|
||||
|
||||
//! @brief Key Blob format.
|
||||
typedef struct KeyBlob
|
||||
{
|
||||
unsigned char key[kAesKeySizeBytes]; // 16 bytes, 128-bits, KEY[A15...A00]
|
||||
unsigned char ctr[kCtrSizeBytes]; // 8 bytes, 64-bits, CTR[C7...C0]
|
||||
unsigned int srtaddr; // region start, STRADDR[31 - 10]
|
||||
unsigned int endaddr; // region end, ENDADDR[31 - 10]
|
||||
// end of 32-byte area covered by CRC
|
||||
unsigned int zero_fill; // zeros
|
||||
unsigned int key_blob_crc32; // crc32 over 1st 32-bytes
|
||||
// end of 40 byte (5*64-bit) key blob data
|
||||
unsigned char expanded_wrap_data[8]; // 8 bytes, used for wrap expanded data
|
||||
// end of 48 byte (6*64-bit) wrap data
|
||||
unsigned char unused_filler[16]; // unused fill to 64 bytes
|
||||
} keyblob_t;
|
||||
|
||||
void populateKeyBlob(keyblob_t *blob, uint32_t start, uint32_t end, const char *keyHex, const char *counterHex);
|
||||
void encrypt(uint32_t length, uint8_t *data, AESKey<128> *key, AESCounter<128> *counter);
|
||||
bool getOptionValues(OptionContext &opt, const char **key, const char **ctr, uint32_t *start, uint32_t *end);
|
||||
|
||||
uint32_t m_id; //!< Unique identifier.
|
||||
option_vector_t m_options; //!< List of option entries.
|
||||
};
|
||||
|
||||
}; // namespace elftosb
|
||||
|
||||
#endif // _Keyblob_h_
|
||||
48
apps/elftosb/common/KeyblobEntry.h
Normal file
48
apps/elftosb/common/KeyblobEntry.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* File: KeyblobEntry.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
#if !defined(_KeyblobEntry_h_)
|
||||
#define _KeyblobEntry_h_
|
||||
|
||||
#include "smart_ptr.h"
|
||||
#include "OptionContext.h"
|
||||
|
||||
namespace elftosb
|
||||
{
|
||||
/*!
|
||||
* @brief Base class for data model of sections of the output file.
|
||||
*/
|
||||
class KeyblobEntry
|
||||
{
|
||||
public:
|
||||
KeyblobEntry()
|
||||
: m_id(0)
|
||||
, m_options(0)
|
||||
{
|
||||
}
|
||||
KeyblobEntry(uint32_t identifier)
|
||||
: m_id(identifier)
|
||||
, m_options(0)
|
||||
{
|
||||
}
|
||||
virtual ~KeyblobEntry() {}
|
||||
void setIdentifier(uint32_t identifier) { m_id = identifier; }
|
||||
uint32_t getIdentifier() const { return m_id; }
|
||||
//! \brief Set the option context.
|
||||
//!
|
||||
//! The keyblob entry object will assume ownership of the option context
|
||||
//! and delete it when the section is deleted.
|
||||
inline void setOptions(OptionContext *context) { m_options = context; }
|
||||
//! \brief Return the option context.
|
||||
inline const OptionContext *getOptions() const { return m_options; }
|
||||
protected:
|
||||
uint32_t m_id; //!< Unique identifier.
|
||||
smart_ptr<OptionContext> m_options; //!< Options associated with just this keyblob entry.
|
||||
};
|
||||
|
||||
}; // namespace elftosb
|
||||
|
||||
#endif // _KeyblobEntry_h_
|
||||
90
apps/elftosb/common/Logging.cpp
Normal file
90
apps/elftosb/common/Logging.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* File: Logging.cpp
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
|
||||
#include "Logging.h"
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include "smart_ptr.h"
|
||||
|
||||
// init global logger to null
|
||||
Logger *Log::s_logger = NULL;
|
||||
|
||||
void Logger::log(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
log(m_level, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void Logger::log(log_level_t level, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
log(level, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void Logger::log(const char *fmt, va_list args)
|
||||
{
|
||||
log(m_level, fmt, args);
|
||||
}
|
||||
|
||||
//! Allocates a temporary 1KB buffer which is used to hold the
|
||||
//! formatted string.
|
||||
void Logger::log(log_level_t level, const char *fmt, va_list args)
|
||||
{
|
||||
smart_array_ptr<char> buffer = new char[1024];
|
||||
vsprintf(buffer, fmt, args);
|
||||
if (level <= m_filter)
|
||||
{
|
||||
_log(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void Log::log(const char *fmt, ...)
|
||||
{
|
||||
if (s_logger)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
s_logger->log(fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
}
|
||||
|
||||
void Log::log(const std::string &msg)
|
||||
{
|
||||
if (s_logger)
|
||||
{
|
||||
s_logger->log(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void Log::log(Logger::log_level_t level, const char *fmt, ...)
|
||||
{
|
||||
if (s_logger)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
s_logger->log(level, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
}
|
||||
|
||||
void Log::log(Logger::log_level_t level, const std::string &msg)
|
||||
{
|
||||
if (s_logger)
|
||||
{
|
||||
s_logger->log(level, msg);
|
||||
}
|
||||
}
|
||||
|
||||
void StdoutLogger::_log(const char *msg)
|
||||
{
|
||||
printf("%s", msg);
|
||||
}
|
||||
219
apps/elftosb/common/Logging.h
Normal file
219
apps/elftosb/common/Logging.h
Normal file
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
* File: Logging.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
#if !defined(_Logging_h_)
|
||||
#define _Logging_h_
|
||||
|
||||
#include <string>
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
/*!
|
||||
* \brief Base logger class.
|
||||
*
|
||||
* There are two types of logging levels that are used by this class. First
|
||||
* there is the filter level. Any log message that is assigned a level
|
||||
* higher than the current filter level is discarded. Secondly there is the
|
||||
* current output level. Log messages that do not have their own level
|
||||
* use the current output level to determine if they should be shown or
|
||||
* not.
|
||||
*
|
||||
* The two methods setFilterLevel() and setOutputLevel() set the filter
|
||||
* and default output logging levels, respectively. There are corresponding
|
||||
* getter methods as well. Both the filter and output levels are
|
||||
* initialized to #INFO during object construction.
|
||||
*
|
||||
* Most use of the logger classes is expected to be through the Log
|
||||
* class. It provides static logging methods that call through to a global
|
||||
* singleton logger instance. There is also a Log::SetOutputLevel utility
|
||||
* class that makes it extremely easiy to temporarily change the default
|
||||
* output logging level.
|
||||
*
|
||||
* Of all the overloaded log() methods in this class, none of them are
|
||||
* really expected to be reimplemented by subclasses. Instead, there is
|
||||
* the single protected _log() method that takes a simple string pointer.
|
||||
* The other log methods all wind up calling _log(), so it provides a
|
||||
* single point to override. In fact, _log() is pure virtual, so subclasses
|
||||
* must implement it.
|
||||
*
|
||||
* \see Log
|
||||
*/
|
||||
class Logger
|
||||
{
|
||||
public:
|
||||
//! \brief Logging levels.
|
||||
enum log_level_t
|
||||
{
|
||||
URGENT = 0, //!< The lowest level, for messages that must always be logged.
|
||||
ERROR, //!< For fatal error messages.
|
||||
WARNING, //!< For non-fatal warning messages.
|
||||
INFO, //!< The normal log level, for status messages.
|
||||
INFO2, //!< For verbose status messages.
|
||||
DEBUG, //!< For internal reporting.
|
||||
DEBUG2 //!< Highest log level; verbose debug logging.
|
||||
};
|
||||
|
||||
public:
|
||||
//! \brief Default constructor.
|
||||
Logger()
|
||||
: m_filter(INFO)
|
||||
, m_level(INFO)
|
||||
{
|
||||
}
|
||||
|
||||
//! \brief Destructor.
|
||||
virtual ~Logger() {}
|
||||
//! \name Logging levels
|
||||
//@{
|
||||
//! \brief Changes the logging level to \a level.
|
||||
inline void setFilterLevel(log_level_t level) { m_filter = level; }
|
||||
//! \brief Returns the current logging filter level.
|
||||
inline log_level_t getFilterLevel() const { return m_filter; }
|
||||
//! \brief Changes the logging output level to \a level.
|
||||
inline void setOutputLevel(log_level_t level) { m_level = level; }
|
||||
//! \brief Returns the current logging output level.
|
||||
inline log_level_t getOutputLevel() const { return m_level; }
|
||||
//@}
|
||||
|
||||
//! \name Logging
|
||||
//@{
|
||||
//! \brief Log with format.
|
||||
virtual void log(const char *fmt, ...);
|
||||
|
||||
//! \brief Log a string object.
|
||||
virtual void log(const std::string &msg) { log(msg.c_str()); }
|
||||
//! \brief Log with format at a specific output level.
|
||||
virtual void log(log_level_t level, const char *fmt, ...);
|
||||
|
||||
//! \brief Log a string output at a specific output level.
|
||||
virtual void log(log_level_t level, const std::string &msg) { log(level, msg.c_str()); }
|
||||
//! \brief Log with format using an argument list.
|
||||
virtual void log(const char *fmt, va_list args);
|
||||
|
||||
//! \brief Log with format using an argument with a specific output level.
|
||||
virtual void log(log_level_t level, const char *fmt, va_list args);
|
||||
//@}
|
||||
|
||||
protected:
|
||||
log_level_t m_filter; //!< The current logging filter level.
|
||||
log_level_t m_level; //!< The current log output level.
|
||||
|
||||
protected:
|
||||
//! \brief The base pure virtual logging function implemented by subclasses.
|
||||
virtual void _log(const char *msg) = 0;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Wraps a set of static functions for easy global logging access.
|
||||
*
|
||||
* This class has a set of static methods that make it easy to access a global
|
||||
* logger instance without having to worry about extern symbols. It does this
|
||||
* by keeping a static member variable pointing at the singleton logger instance,
|
||||
* which is set with the setLogger() static method.
|
||||
*
|
||||
* There is also an inner utility class called SetOutputLevel that uses
|
||||
* C++ scoping rules to temporarily change the output logging level. When the
|
||||
* SetOutputLevel instance falls out of scope the output level is restored
|
||||
* to the previous value.
|
||||
*/
|
||||
class Log
|
||||
{
|
||||
public:
|
||||
//! \name Singleton logger access
|
||||
//@{
|
||||
//! \brief Returns the current global logger singleton.
|
||||
static inline Logger *getLogger() { return s_logger; }
|
||||
//! \brief Sets the global logger singleton instance.
|
||||
static inline void setLogger(Logger *logger) { s_logger = logger; }
|
||||
//@}
|
||||
|
||||
//! \name Logging
|
||||
//@{
|
||||
//! \brief Log with format.
|
||||
static void log(const char *fmt, ...);
|
||||
|
||||
//! \brief Log a string object.
|
||||
static void log(const std::string &msg);
|
||||
|
||||
//! \brief Log with format at a specific output level.
|
||||
static void log(Logger::log_level_t level, const char *fmt, ...);
|
||||
|
||||
//! \brief Log a string output at a specific output level.
|
||||
static void log(Logger::log_level_t level, const std::string &msg);
|
||||
//@}
|
||||
|
||||
protected:
|
||||
static Logger *s_logger; //!< The single global logger instance.
|
||||
|
||||
public:
|
||||
/*!
|
||||
* \brief Utility class to temporarily change the logging output level.
|
||||
*
|
||||
* This class will change the current logging output level of a given
|
||||
* logger instance. Then when it falls out of scope it will set the
|
||||
* level back to what it was originally.
|
||||
*
|
||||
* Use like this:
|
||||
* \code
|
||||
* // output level is some value here
|
||||
* {
|
||||
* Log::SetOutputLevel leveler(Logger::DEBUG);
|
||||
* // now output level is DEBUG
|
||||
* Log::log("my debug message 1");
|
||||
* Log::log("my debug message 2");
|
||||
* }
|
||||
* // output level is restored to previous value
|
||||
* \endcode
|
||||
*/
|
||||
class SetOutputLevel
|
||||
{
|
||||
public:
|
||||
//! \brief Default constructor.
|
||||
//!
|
||||
//! Saves the current logging output level of the global logger,
|
||||
//! as managed by the Log class, and sets the new level to \a level.
|
||||
SetOutputLevel(Logger::log_level_t level)
|
||||
: m_logger(Log::getLogger())
|
||||
, m_saved(Logger::INFO)
|
||||
{
|
||||
assert(m_logger);
|
||||
m_saved = m_logger->getOutputLevel();
|
||||
m_logger->setOutputLevel(level);
|
||||
}
|
||||
|
||||
//! \brief Constructor.
|
||||
//!
|
||||
//! Saves the current logging output level of \a logger and sets
|
||||
//! the new level to \a level.
|
||||
SetOutputLevel(Logger *logger, Logger::log_level_t level)
|
||||
: m_logger(logger)
|
||||
, m_saved(logger->getOutputLevel())
|
||||
{
|
||||
assert(m_logger);
|
||||
m_logger->setOutputLevel(level);
|
||||
}
|
||||
|
||||
//! \brief Destructor.
|
||||
//!
|
||||
//! Restores the saved logging output level.
|
||||
~SetOutputLevel() { m_logger->setOutputLevel(m_saved); }
|
||||
protected:
|
||||
Logger *m_logger; //!< The logger instance we're controlling.
|
||||
Logger::log_level_t m_saved; //!< Original logging output level.
|
||||
};
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Simple logger that writes to stdout.
|
||||
*/
|
||||
class StdoutLogger : public Logger
|
||||
{
|
||||
protected:
|
||||
//! \brief Logs the message to stdout.
|
||||
virtual void _log(const char *msg);
|
||||
};
|
||||
|
||||
#endif // _Logging_h_
|
||||
87
apps/elftosb/common/Operation.cpp
Normal file
87
apps/elftosb/common/Operation.cpp
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* File: Operation.cpp
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
|
||||
#include "Operation.h"
|
||||
|
||||
using namespace elftosb;
|
||||
|
||||
//! The operation object takes ownership of \a source.
|
||||
//!
|
||||
//! Cross references between the target and source are updated.
|
||||
void LoadOperation::setSource(DataSource *source)
|
||||
{
|
||||
m_source = source;
|
||||
|
||||
if (m_target)
|
||||
{
|
||||
m_target->setSource(m_source);
|
||||
}
|
||||
if (m_source)
|
||||
{
|
||||
m_source->setTarget(m_target);
|
||||
}
|
||||
}
|
||||
|
||||
//! The operation object takes ownership of \a target.
|
||||
//!
|
||||
//! Cross references between the target and source are updated.
|
||||
void LoadOperation::setTarget(DataTarget *target)
|
||||
{
|
||||
m_target = target;
|
||||
|
||||
if (m_target)
|
||||
{
|
||||
m_target->setSource(m_source);
|
||||
}
|
||||
if (m_source)
|
||||
{
|
||||
m_source->setTarget(m_target);
|
||||
}
|
||||
}
|
||||
|
||||
void FlashEraseOperation::getRange(uint32_t *start, uint32_t *count) const
|
||||
{
|
||||
if (start)
|
||||
{
|
||||
*start = m_startAddress;
|
||||
}
|
||||
if (count)
|
||||
{
|
||||
*count = m_byteCount;
|
||||
}
|
||||
}
|
||||
|
||||
void MemEnableOperation::getRange(uint32_t *start, uint32_t *count) const
|
||||
{
|
||||
if (start)
|
||||
{
|
||||
*start = m_startAddress;
|
||||
}
|
||||
if (count)
|
||||
{
|
||||
*count = m_byteCount;
|
||||
}
|
||||
}
|
||||
|
||||
//! Disposes of operations objects in the sequence.
|
||||
OperationSequence::~OperationSequence()
|
||||
{
|
||||
// iterator_t it = begin();
|
||||
// for (; it != end(); ++it)
|
||||
// {
|
||||
// delete it->second;
|
||||
// }
|
||||
}
|
||||
|
||||
void OperationSequence::append(const OperationSequence *other)
|
||||
{
|
||||
const_iterator_t it = other->begin();
|
||||
for (; it != other->end(); ++it)
|
||||
{
|
||||
m_operations.push_back(*it);
|
||||
}
|
||||
}
|
||||
374
apps/elftosb/common/Operation.h
Normal file
374
apps/elftosb/common/Operation.h
Normal file
@@ -0,0 +1,374 @@
|
||||
/*
|
||||
* File: Operation.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
#if !defined(_Operation_h_)
|
||||
#define _Operation_h_
|
||||
|
||||
#include "stdafx.h"
|
||||
#include <vector>
|
||||
#include "DataSource.h"
|
||||
#include "DataTarget.h"
|
||||
#include "smart_ptr.h"
|
||||
#include "keyblob.h"
|
||||
|
||||
namespace elftosb
|
||||
{
|
||||
/*!
|
||||
* \brief Abstract base class for all boot operations.
|
||||
*/
|
||||
class Operation
|
||||
{
|
||||
public:
|
||||
Operation() {}
|
||||
virtual ~Operation() {}
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Load data into memory operation.
|
||||
*/
|
||||
class LoadOperation : public Operation
|
||||
{
|
||||
public:
|
||||
LoadOperation()
|
||||
: Operation()
|
||||
, m_source()
|
||||
, m_target()
|
||||
, m_isDCDLoad(false)
|
||||
{
|
||||
}
|
||||
|
||||
void setSource(DataSource *source);
|
||||
inline DataSource *getSource() { return m_source; }
|
||||
void setTarget(DataTarget *target);
|
||||
inline DataTarget *getTarget() { return m_target; }
|
||||
inline void setDCDLoad(bool isDCD) { m_isDCDLoad = isDCD; }
|
||||
inline bool isDCDLoad() const { return m_isDCDLoad; }
|
||||
protected:
|
||||
smart_ptr<DataSource> m_source;
|
||||
smart_ptr<DataTarget> m_target;
|
||||
bool m_isDCDLoad;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Operation to execute code at a certain address.
|
||||
*/
|
||||
class ExecuteOperation : public Operation
|
||||
{
|
||||
public:
|
||||
enum execute_type_t
|
||||
{
|
||||
kJump,
|
||||
kCall
|
||||
};
|
||||
|
||||
public:
|
||||
ExecuteOperation()
|
||||
: Operation()
|
||||
, m_target()
|
||||
, m_argument(0)
|
||||
, m_type(kCall)
|
||||
, m_isHAB(false)
|
||||
, m_stackPointer(0)
|
||||
, m_isStackPointerSet(false)
|
||||
{
|
||||
}
|
||||
|
||||
inline void setTarget(DataTarget *target) { m_target = target; }
|
||||
inline DataTarget *getTarget() { return m_target; }
|
||||
inline void setArgument(uint32_t arg) { m_argument = arg; }
|
||||
inline uint32_t getArgument() { return m_argument; }
|
||||
inline void setExecuteType(execute_type_t type) { m_type = type; }
|
||||
inline execute_type_t getExecuteType() { return m_type; }
|
||||
inline void setIsHAB(bool isHAB) { m_isHAB = isHAB; }
|
||||
inline bool isHAB() const { return m_isHAB; }
|
||||
inline void setStackPointer(uint32_t sp) { m_stackPointer = sp; }
|
||||
inline uint32_t getStackPointer() { return m_stackPointer; }
|
||||
inline void setIsStackPointerSet(bool isSet) { m_isStackPointerSet = isSet; }
|
||||
inline bool isStackPonterSet() const { return m_isStackPointerSet; }
|
||||
protected:
|
||||
smart_ptr<DataTarget> m_target;
|
||||
uint32_t m_argument;
|
||||
uint32_t m_stackPointer;
|
||||
execute_type_t m_type;
|
||||
bool m_isHAB;
|
||||
bool m_isStackPointerSet;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Authenticate with HAB and execute the entry point.
|
||||
*/
|
||||
class HABExecuteOperation : public ExecuteOperation
|
||||
{
|
||||
public:
|
||||
HABExecuteOperation()
|
||||
: ExecuteOperation()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Operation to switch boot modes.
|
||||
*/
|
||||
class BootModeOperation : public Operation
|
||||
{
|
||||
public:
|
||||
BootModeOperation()
|
||||
: Operation()
|
||||
, m_bootMode(0)
|
||||
{
|
||||
}
|
||||
|
||||
inline void setBootMode(uint32_t mode) { m_bootMode = mode; }
|
||||
inline uint32_t getBootMode() const { return m_bootMode; }
|
||||
protected:
|
||||
uint32_t m_bootMode; //!< The new boot mode value.
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Operation to reset the device.
|
||||
*/
|
||||
class ResetOperation : public Operation
|
||||
{
|
||||
public:
|
||||
ResetOperation()
|
||||
: Operation()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Operation to erase flash memory.
|
||||
*/
|
||||
class FlashEraseOperation : public Operation
|
||||
{
|
||||
public:
|
||||
FlashEraseOperation()
|
||||
: Operation()
|
||||
, m_startAddress(0)
|
||||
, m_byteCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
void setRange(uint32_t start, uint32_t count)
|
||||
{
|
||||
m_startAddress = start;
|
||||
m_byteCount = count;
|
||||
}
|
||||
void getRange(uint32_t *start, uint32_t *count) const;
|
||||
|
||||
protected:
|
||||
uint32_t m_startAddress;
|
||||
uint32_t m_byteCount;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Operation to erase the entire flash memory array.
|
||||
*/
|
||||
class FlashEraseAllOperation : public FlashEraseOperation
|
||||
{
|
||||
public:
|
||||
FlashEraseAllOperation()
|
||||
: FlashEraseOperation()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Operation to erase the entire external flash memory array.
|
||||
*/
|
||||
class FlashEraseAllExternalOperation : public FlashEraseOperation
|
||||
{
|
||||
public:
|
||||
FlashEraseAllExternalOperation()
|
||||
: FlashEraseOperation()
|
||||
, m_memoryId(0)
|
||||
{
|
||||
}
|
||||
|
||||
void setMemoryId(uint32_t memId) { m_memoryId = memId; }
|
||||
uint32_t getMemoryId() const { return m_memoryId; }
|
||||
protected:
|
||||
uint32_t m_memoryId;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Operation to erase the entire flash memory array, unsecure version.
|
||||
*/
|
||||
class FlashEraseAllUnsecureOperation : public FlashEraseOperation
|
||||
{
|
||||
public:
|
||||
FlashEraseAllUnsecureOperation()
|
||||
: FlashEraseOperation()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Operation to enable external memory access.
|
||||
*/
|
||||
class MemEnableOperation : public Operation
|
||||
{
|
||||
public:
|
||||
MemEnableOperation()
|
||||
: Operation()
|
||||
, m_startAddress(0)
|
||||
, m_byteCount(0)
|
||||
, m_memControllerId(0)
|
||||
{
|
||||
}
|
||||
|
||||
void setMemControllerId(uint32_t memControllerId) { m_memControllerId = memControllerId; }
|
||||
uint32_t getMemControllerId() const { return m_memControllerId; }
|
||||
void setRange(uint32_t start, uint32_t count)
|
||||
{
|
||||
m_startAddress = start;
|
||||
m_byteCount = count;
|
||||
}
|
||||
void getRange(uint32_t *start, uint32_t *count) const;
|
||||
|
||||
protected:
|
||||
uint32_t m_startAddress;
|
||||
uint32_t m_byteCount;
|
||||
uint32_t m_memControllerId;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Operation to program persistent bits.
|
||||
*/
|
||||
class ProgramOperation : public LoadOperation
|
||||
{
|
||||
public:
|
||||
//! \brief Default constructor.
|
||||
ProgramOperation()
|
||||
: LoadOperation()
|
||||
, m_memSpace(0)
|
||||
{
|
||||
}
|
||||
|
||||
//! \brief Constructor. Takes a memory space argument.
|
||||
ProgramOperation(uint32_t memSpace)
|
||||
: LoadOperation()
|
||||
, m_memSpace(memSpace)
|
||||
{
|
||||
}
|
||||
|
||||
void setMemorySpace(uint32_t memSpace) { m_memSpace = memSpace; }
|
||||
uint32_t getMemorySpace() const { return m_memSpace; }
|
||||
protected:
|
||||
uint32_t m_memSpace;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Operation to wrap and program keys.
|
||||
*/
|
||||
class KeywrapOperation : public LoadOperation
|
||||
{
|
||||
public:
|
||||
//! \brief Default constructor.
|
||||
KeywrapOperation()
|
||||
: LoadOperation()
|
||||
, m_keyblob()
|
||||
{
|
||||
}
|
||||
|
||||
//! \brief Constructor. Takes a keyblob argument.
|
||||
KeywrapOperation(Keyblob *keyblob)
|
||||
: LoadOperation()
|
||||
, m_keyblob(keyblob)
|
||||
{
|
||||
}
|
||||
|
||||
void setKeyblob(Keyblob *keyblob) { m_keyblob = keyblob; }
|
||||
Keyblob *getKeyblob() { return m_keyblob; }
|
||||
protected:
|
||||
smart_ptr<Keyblob> m_keyblob; //!< Active keyblob during this load.
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Operation to encrypt data for OTFAD.
|
||||
*/
|
||||
class EncryptOperation : public LoadOperation
|
||||
{
|
||||
public:
|
||||
//! \brief Default constructor.
|
||||
EncryptOperation()
|
||||
: LoadOperation()
|
||||
, m_keyblob()
|
||||
{
|
||||
}
|
||||
|
||||
//! \brief Constructor. Takes a keyblob argument.
|
||||
EncryptOperation(Keyblob *keyblob)
|
||||
: LoadOperation()
|
||||
, m_keyblob(keyblob)
|
||||
{
|
||||
}
|
||||
|
||||
void setKeyblob(Keyblob *keyblob) { m_keyblob = keyblob; }
|
||||
Keyblob *getKeyblob() { return m_keyblob; }
|
||||
protected:
|
||||
smart_ptr<Keyblob> m_keyblob; //!< Active keyblob during this load.
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Ordered sequence of operations.
|
||||
*
|
||||
* The operation objects owned by the sequence are \e not deleted when the
|
||||
* sequence is destroyed. The owner of the sequence must manually delete
|
||||
* the operation objects.
|
||||
*/
|
||||
class OperationSequence
|
||||
{
|
||||
public:
|
||||
typedef std::vector<Operation *> operation_list_t; //!< Type for a list of operation objects.
|
||||
typedef operation_list_t::iterator iterator_t; //!< Iterator over operations.
|
||||
typedef operation_list_t::const_iterator const_iterator_t; //!< Const iterator over operations.
|
||||
|
||||
public:
|
||||
//! \brief Default constructor.
|
||||
OperationSequence() {}
|
||||
//! \brief Constructor. Makes a one-element sequence from \a soleElement.
|
||||
OperationSequence(Operation *soleElement) { m_operations.push_back(soleElement); }
|
||||
//! \brief Destructor.
|
||||
virtual ~OperationSequence();
|
||||
|
||||
//! \name Iterators
|
||||
//@{
|
||||
inline iterator_t begin() { return m_operations.begin(); }
|
||||
inline const_iterator_t begin() const { return m_operations.begin(); }
|
||||
inline iterator_t end() { return m_operations.end(); }
|
||||
inline const_iterator_t end() const { return m_operations.end(); }
|
||||
//@}
|
||||
|
||||
inline Operation *operator[](unsigned index) const { return m_operations[index]; }
|
||||
//! \name Status
|
||||
//@{
|
||||
//! \brief Returns the number of operations in the sequence.
|
||||
inline unsigned getCount() const { return m_operations.size(); }
|
||||
//@}
|
||||
|
||||
//! \name Operations
|
||||
//@{
|
||||
//! \brief Append one operation object to the sequence.
|
||||
inline void append(Operation *op) { m_operations.push_back(op); }
|
||||
//! \brief Append the contents of \a other onto this sequence.
|
||||
void append(const OperationSequence *other);
|
||||
|
||||
//! \brief Appends \a other onto this sequence.
|
||||
OperationSequence &operator+=(const OperationSequence *other)
|
||||
{
|
||||
append(other);
|
||||
return *this;
|
||||
}
|
||||
//@}
|
||||
|
||||
protected:
|
||||
operation_list_t m_operations; //!< The list of operations.
|
||||
};
|
||||
|
||||
}; // namespace elftosb
|
||||
|
||||
#endif // _Operation_h_
|
||||
51
apps/elftosb/common/OptionContext.h
Normal file
51
apps/elftosb/common/OptionContext.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* File: OptionContext.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
#if !defined(_OptionContext_h_)
|
||||
#define _OptionContext_h_
|
||||
|
||||
#include <string>
|
||||
#include "Value.h"
|
||||
|
||||
namespace elftosb
|
||||
{
|
||||
/*!
|
||||
* \brief Pure abstract interface class to a table of options.
|
||||
*/
|
||||
class OptionContext
|
||||
{
|
||||
public:
|
||||
//! Make the dtor virtual.
|
||||
virtual ~OptionContext() {}
|
||||
//! \brief Detemine whether the named option is present in the table.
|
||||
//! \param name The name of the option to query.
|
||||
//! \retval true The option is present and has a value.
|
||||
//! \retval false No option with that name is in the table.
|
||||
virtual bool hasOption(const std::string &name) const = 0;
|
||||
|
||||
//! \brief Returns the option's value.
|
||||
//! \param name The name of the option.
|
||||
//! \return The value for the option named \a name.
|
||||
//! \retval NULL No option is in the table with that name.
|
||||
virtual const Value *getOption(const std::string &name) const = 0;
|
||||
|
||||
//! \brief Adds or changes an option's value.
|
||||
//!
|
||||
//! If the option was not already present in the table, it is added.
|
||||
//! Otherwise the old value is replaced.
|
||||
//!
|
||||
//! \param name The option's name.
|
||||
//! \param value New value for the option.
|
||||
virtual void setOption(const std::string &name, Value *value) = 0;
|
||||
|
||||
//! \brief Removes an option from the table.
|
||||
//! \param name The name of the option to remove.
|
||||
virtual void deleteOption(const std::string &name) = 0;
|
||||
};
|
||||
|
||||
}; // namespace elftosb
|
||||
|
||||
#endif // _OptionContext_h_
|
||||
168
apps/elftosb/common/OptionDictionary.cpp
Normal file
168
apps/elftosb/common/OptionDictionary.cpp
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* File: OptionDictionary.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
|
||||
#include "OptionDictionary.h"
|
||||
|
||||
using namespace elftosb;
|
||||
|
||||
//! Deletes all of the option values that have been assigned locally.
|
||||
//!
|
||||
OptionDictionary::~OptionDictionary()
|
||||
{
|
||||
option_map_t::iterator it = m_options.begin();
|
||||
for (; it != m_options.end(); ++it)
|
||||
{
|
||||
if (it->second.m_value)
|
||||
{
|
||||
delete it->second.m_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//! If a parent context has been set and the option does not exist in
|
||||
//! this instance, then the parent is asked if it contains the option.
|
||||
//!
|
||||
//! \param name The name of the option to query.
|
||||
//! \retval true The option is present in this instance or one of the parent.
|
||||
//! \retval false No option with that name is in the dictionary, or any parent
|
||||
bool OptionDictionary::hasOption(const std::string &name) const
|
||||
{
|
||||
bool hasIt = (m_options.find(name) != m_options.end());
|
||||
if (!hasIt && m_parent)
|
||||
{
|
||||
return m_parent->hasOption(name);
|
||||
}
|
||||
return hasIt;
|
||||
}
|
||||
|
||||
//! If this object does not contain an option with the name of \a name,
|
||||
//! then the parent is asked for the value (if a parent has been set).
|
||||
//!
|
||||
//! \param name The name of the option.
|
||||
//! \return The value for the option named \a name.
|
||||
//! \retval NULL No option is in the table with that name. An option may also
|
||||
//! explicitly be set to a NULL value. The only way to tell the difference
|
||||
//! is to use the hasOption() method.
|
||||
const Value *OptionDictionary::getOption(const std::string &name) const
|
||||
{
|
||||
option_map_t::const_iterator it = m_options.find(name);
|
||||
if (it == m_options.end())
|
||||
{
|
||||
if (m_parent)
|
||||
{
|
||||
return m_parent->getOption(name);
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return it->second.m_value;
|
||||
}
|
||||
|
||||
//! If the option was not already present in the table, it is added.
|
||||
//! Otherwise the old value is replaced. The option is always set locally;
|
||||
//! parent objects are never modified.
|
||||
//!
|
||||
//! If the option has been locked with a call to lockOption() before trying
|
||||
//! to set its value, the setOption() is effectively ignored. To tell if
|
||||
//! an option is locked, use the isOptionLocked() method.
|
||||
//!
|
||||
//! \warning If the option already had a value, that previous value is deleted.
|
||||
//! This means that it cannot currently be in use by another piece of code.
|
||||
//! See the note in getOption().
|
||||
//!
|
||||
//! \param name The option's name.
|
||||
//! \param value New value for the option.
|
||||
void OptionDictionary::setOption(const std::string &name, Value *value)
|
||||
{
|
||||
option_map_t::iterator it = m_options.find(name);
|
||||
OptionValue newValue;
|
||||
|
||||
// delete the option value instance before replacing it
|
||||
if (it != m_options.end())
|
||||
{
|
||||
// Cannot modify value if locked.
|
||||
if (it->second.m_isLocked)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (it->second.m_value)
|
||||
{
|
||||
delete it->second.m_value;
|
||||
}
|
||||
|
||||
// save previous locked value
|
||||
newValue.m_isLocked = it->second.m_isLocked;
|
||||
}
|
||||
|
||||
// set new option value
|
||||
newValue.m_value = value;
|
||||
m_options[name] = newValue;
|
||||
}
|
||||
|
||||
//! \param name The name of the option to remove.
|
||||
//!
|
||||
void OptionDictionary::deleteOption(const std::string &name)
|
||||
{
|
||||
if (m_options.find(name) != m_options.end())
|
||||
{
|
||||
if (m_options[name].m_value)
|
||||
{
|
||||
delete m_options[name].m_value;
|
||||
}
|
||||
m_options.erase(name);
|
||||
}
|
||||
}
|
||||
|
||||
//! \param name Name of the option to query.
|
||||
//!
|
||||
//! \return True if the option is locked, false if unlocked or not present.
|
||||
//!
|
||||
bool OptionDictionary::isOptionLocked(const std::string &name) const
|
||||
{
|
||||
option_map_t::const_iterator it = m_options.find(name);
|
||||
if (it != m_options.end())
|
||||
{
|
||||
return it->second.m_isLocked;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//! \param name Name of the option to lock.
|
||||
//!
|
||||
void OptionDictionary::lockOption(const std::string &name)
|
||||
{
|
||||
if (!hasOption(name))
|
||||
{
|
||||
m_options[name].m_value = 0;
|
||||
}
|
||||
|
||||
m_options[name].m_isLocked = true;
|
||||
}
|
||||
|
||||
//! \param name Name of the option to unlock.
|
||||
//!
|
||||
void OptionDictionary::unlockOption(const std::string &name)
|
||||
{
|
||||
if (!hasOption(name))
|
||||
{
|
||||
m_options[name].m_value = 0;
|
||||
}
|
||||
|
||||
m_options[name].m_isLocked = false;
|
||||
}
|
||||
|
||||
//! Simply calls getOption().
|
||||
//!
|
||||
const Value *OptionDictionary::operator[](const std::string &name) const
|
||||
{
|
||||
return getOption(name);
|
||||
}
|
||||
115
apps/elftosb/common/OptionDictionary.h
Normal file
115
apps/elftosb/common/OptionDictionary.h
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* File: OptionDictionary.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
#if !defined(_OptionDictionary_h_)
|
||||
#define _OptionDictionary_h_
|
||||
|
||||
#include "OptionContext.h"
|
||||
#include <map>
|
||||
|
||||
namespace elftosb
|
||||
{
|
||||
/*!
|
||||
* \brief Concrete implementation of OptionContext.
|
||||
*
|
||||
* This context subclass supports having a parent context. If an option is not
|
||||
* found in the receiving instance, the request is passed to the parent.
|
||||
* The hasOption() and getOption() methods will ask up the parent chain
|
||||
* if the requested option does not exist in the receiving instance.
|
||||
* But the setOption() and deleteOption() methods only operate locally,
|
||||
* on the instance on which they were called. This allows a caller to
|
||||
* locally override an option value without affecting any of the parent
|
||||
* contexts.
|
||||
*/
|
||||
class OptionDictionary : public OptionContext
|
||||
{
|
||||
public:
|
||||
//! \brief Default constructor.
|
||||
OptionDictionary()
|
||||
: m_parent(0)
|
||||
{
|
||||
}
|
||||
|
||||
//! \brief Constructor taking a parent context.
|
||||
OptionDictionary(OptionContext *parent)
|
||||
: m_parent(parent)
|
||||
{
|
||||
}
|
||||
|
||||
//! \brief Destructor.
|
||||
~OptionDictionary();
|
||||
|
||||
//! \name Parents
|
||||
//@{
|
||||
//! \brief Returns the current parent context.
|
||||
//! \return The current parent context instance.
|
||||
//! \retval NULL No parent has been set.
|
||||
inline OptionContext *getParent() const { return m_parent; }
|
||||
//! \brief Change the parent context.
|
||||
//! \param newParent The parent context object. May be NULL, in which case
|
||||
//! the object will no longer have a parent context.
|
||||
inline void setParent(OptionContext *newParent) { m_parent = newParent; }
|
||||
//@}
|
||||
|
||||
//! \name Options
|
||||
//@{
|
||||
//! \brief Detemine whether the named option is present in the table.
|
||||
virtual bool hasOption(const std::string &name) const;
|
||||
|
||||
//! \brief Returns the option's value.
|
||||
virtual const Value *getOption(const std::string &name) const;
|
||||
|
||||
//! \brief Adds or changes an option's value.
|
||||
virtual void setOption(const std::string &name, Value *value);
|
||||
|
||||
//! \brief Removes an option from the table.
|
||||
virtual void deleteOption(const std::string &name);
|
||||
//@}
|
||||
|
||||
//! \name Locking
|
||||
//@{
|
||||
//! \brief Returns true if the specified option is locked from further changes.
|
||||
bool isOptionLocked(const std::string &name) const;
|
||||
|
||||
//! \brief Prevent further modifications of an option's value.
|
||||
void lockOption(const std::string &name);
|
||||
|
||||
//! \brief Allow an option to be changed.
|
||||
void unlockOption(const std::string &name);
|
||||
//@}
|
||||
|
||||
//! \name Operators
|
||||
//@{
|
||||
//! \brief Indexing operator; returns the value for the option \a name.
|
||||
const Value *operator[](const std::string &name) const;
|
||||
//@}
|
||||
|
||||
protected:
|
||||
OptionContext *m_parent; //!< Our parent context.
|
||||
|
||||
/*!
|
||||
* \brief Information about one option's value.
|
||||
*/
|
||||
struct OptionValue
|
||||
{
|
||||
Value *m_value; //!< The object for this option's value.
|
||||
bool m_isLocked; //!< True if this value is locked from further changes.
|
||||
|
||||
//! \brief Constructor.
|
||||
OptionValue()
|
||||
: m_value(0)
|
||||
, m_isLocked(false)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::map<std::string, OptionValue> option_map_t; //!< Map from option name to value.
|
||||
option_map_t m_options; //!< The option dictionary.
|
||||
};
|
||||
|
||||
}; // namespace elftosb
|
||||
|
||||
#endif // _OptionDictionary_h_
|
||||
8
apps/elftosb/common/OutputSection.cpp
Normal file
8
apps/elftosb/common/OutputSection.cpp
Normal file
@@ -0,0 +1,8 @@
|
||||
/*
|
||||
* File: OutputSection.cpp
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
|
||||
#include "OutputSection.h"
|
||||
88
apps/elftosb/common/OutputSection.h
Normal file
88
apps/elftosb/common/OutputSection.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* File: OutputSection.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
#if !defined(_OutputSection_h_)
|
||||
#define _OutputSection_h_
|
||||
|
||||
#include "Operation.h"
|
||||
#include "smart_ptr.h"
|
||||
#include "Blob.h"
|
||||
#include "OptionContext.h"
|
||||
|
||||
namespace elftosb
|
||||
{
|
||||
/*!
|
||||
* @brief Base class for data model of sections of the output file.
|
||||
*/
|
||||
class OutputSection
|
||||
{
|
||||
public:
|
||||
OutputSection()
|
||||
: m_id(0)
|
||||
, m_options(0)
|
||||
{
|
||||
}
|
||||
OutputSection(uint32_t identifier)
|
||||
: m_id(identifier)
|
||||
, m_options(0)
|
||||
{
|
||||
}
|
||||
virtual ~OutputSection() {}
|
||||
void setIdentifier(uint32_t identifier) { m_id = identifier; }
|
||||
uint32_t getIdentifier() const { return m_id; }
|
||||
//! \brief Set the option context.
|
||||
//!
|
||||
//! The output section object will assume ownership of the option context
|
||||
//! and delete it when the section is deleted.
|
||||
inline void setOptions(OptionContext *context) { m_options = context; }
|
||||
//! \brief Return the option context.
|
||||
inline const OptionContext *getOptions() const { return m_options; }
|
||||
protected:
|
||||
uint32_t m_id; //!< Unique identifier.
|
||||
smart_ptr<OptionContext> m_options; //!< Options associated with just this section.
|
||||
};
|
||||
|
||||
/*!
|
||||
* @brief A section of the output that contains boot operations.
|
||||
*/
|
||||
class OperationSequenceSection : public OutputSection
|
||||
{
|
||||
public:
|
||||
OperationSequenceSection()
|
||||
: OutputSection()
|
||||
{
|
||||
}
|
||||
OperationSequenceSection(uint32_t identifier)
|
||||
: OutputSection(identifier)
|
||||
{
|
||||
}
|
||||
|
||||
OperationSequence &getSequence() { return m_sequence; }
|
||||
protected:
|
||||
OperationSequence m_sequence;
|
||||
};
|
||||
|
||||
/*!
|
||||
* @brief A section of the output file that contains arbitrary binary data.
|
||||
*/
|
||||
class BinaryDataSection : public OutputSection, public Blob
|
||||
{
|
||||
public:
|
||||
BinaryDataSection()
|
||||
: OutputSection()
|
||||
, Blob()
|
||||
{
|
||||
}
|
||||
BinaryDataSection(uint32_t identifier)
|
||||
: OutputSection(identifier)
|
||||
, Blob()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
}; // namespace elftosb
|
||||
|
||||
#endif // _OutputSection_h_
|
||||
81
apps/elftosb/common/Random.cpp
Normal file
81
apps/elftosb/common/Random.cpp
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* File: Random.cpp
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
|
||||
#include "Random.h"
|
||||
#include <stdexcept>
|
||||
|
||||
#ifdef WIN32
|
||||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0400
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#include <wincrypt.h>
|
||||
#else // WIN32
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#endif // WIN32
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
MicrosoftCryptoProvider::MicrosoftCryptoProvider()
|
||||
{
|
||||
if (!CryptAcquireContext(&m_hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
|
||||
{
|
||||
throw std::runtime_error("CryptAcquireContext");
|
||||
}
|
||||
}
|
||||
|
||||
MicrosoftCryptoProvider::~MicrosoftCryptoProvider()
|
||||
{
|
||||
CryptReleaseContext(m_hProvider, 0);
|
||||
}
|
||||
|
||||
#endif // WIN32
|
||||
|
||||
RandomNumberGenerator::RandomNumberGenerator()
|
||||
{
|
||||
#ifndef WIN32
|
||||
m_fd = open("/dev/urandom", O_RDONLY);
|
||||
if (m_fd == -1)
|
||||
{
|
||||
throw std::runtime_error("open /dev/urandom");
|
||||
}
|
||||
#endif // WIN32
|
||||
}
|
||||
|
||||
RandomNumberGenerator::~RandomNumberGenerator()
|
||||
{
|
||||
#ifndef WIN32
|
||||
close(m_fd);
|
||||
#endif // WIN32
|
||||
}
|
||||
|
||||
uint8_t RandomNumberGenerator::generateByte()
|
||||
{
|
||||
uint8_t result;
|
||||
generateBlock(&result, 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
void RandomNumberGenerator::generateBlock(uint8_t *output, unsigned count)
|
||||
{
|
||||
#ifdef WIN32
|
||||
#ifdef WORKAROUND_MS_BUG_Q258000
|
||||
static MicrosoftCryptoProvider m_provider;
|
||||
#endif
|
||||
if (!CryptGenRandom(m_provider.GetProviderHandle(), count, output))
|
||||
{
|
||||
throw std::runtime_error("CryptGenRandom");
|
||||
}
|
||||
#else // WIN32
|
||||
if (read(m_fd, output, count) != count)
|
||||
{
|
||||
throw std::runtime_error("read /dev/urandom");
|
||||
}
|
||||
#endif // WIN32
|
||||
}
|
||||
56
apps/elftosb/common/Random.h
Normal file
56
apps/elftosb/common/Random.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* File: Random.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
#if !defined(_Random_h_)
|
||||
#define _Random_h_
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#ifdef WIN32
|
||||
/*!
|
||||
* This class is from the crypto++ library.
|
||||
*/
|
||||
class MicrosoftCryptoProvider
|
||||
{
|
||||
public:
|
||||
MicrosoftCryptoProvider();
|
||||
~MicrosoftCryptoProvider();
|
||||
#if defined(_WIN64)
|
||||
typedef unsigned __int64 ProviderHandle; // type HCRYPTPROV, avoid #include <windows.h>
|
||||
#else
|
||||
typedef unsigned long ProviderHandle;
|
||||
#endif
|
||||
ProviderHandle GetProviderHandle() const { return m_hProvider; }
|
||||
private:
|
||||
ProviderHandle m_hProvider;
|
||||
};
|
||||
|
||||
#pragma comment(lib, "advapi32.lib")
|
||||
#endif // WIN32
|
||||
|
||||
/*!
|
||||
* Encapsulates the Windows CryptoAPI's CryptGenRandom or /dev/urandom on Unix systems.
|
||||
*/
|
||||
class RandomNumberGenerator
|
||||
{
|
||||
public:
|
||||
RandomNumberGenerator();
|
||||
~RandomNumberGenerator();
|
||||
|
||||
uint8_t generateByte();
|
||||
void generateBlock(uint8_t *output, unsigned count);
|
||||
|
||||
protected:
|
||||
#ifdef WIN32
|
||||
#ifndef WORKAROUND_MS_BUG_Q258000
|
||||
MicrosoftCryptoProvider m_provider;
|
||||
#endif
|
||||
#else // WIN32
|
||||
int m_fd;
|
||||
#endif // WIN32
|
||||
};
|
||||
|
||||
#endif // _Random_h_
|
||||
85
apps/elftosb/common/RijndaelCBCMAC.cpp
Normal file
85
apps/elftosb/common/RijndaelCBCMAC.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* File: RijndaelCBCMAC.cpp
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
|
||||
#include "RijndaelCBCMAC.h"
|
||||
#include "rijndael.h"
|
||||
#include <assert.h>
|
||||
#include "Logging.h"
|
||||
|
||||
void logHexArray(Logger::log_level_t level, const uint8_t *bytes, unsigned count);
|
||||
|
||||
//! \param key The key to use as the CBC-MAC secret.
|
||||
//! \param iv Initialization vector. Defaults to zero if not provided.
|
||||
RijndaelCBCMAC::RijndaelCBCMAC(const AESKey<128> &key, const uint8_t *iv)
|
||||
: m_key(key)
|
||||
{
|
||||
if (iv)
|
||||
{
|
||||
memcpy(m_mac, iv, sizeof(m_mac));
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(m_mac, 0, sizeof(m_mac));
|
||||
}
|
||||
}
|
||||
|
||||
//! \param data Pointer to data to process.
|
||||
//! \param length Number of bytes to process. Must be evenly divisible by #BLOCK_SIZE.
|
||||
void RijndaelCBCMAC::update(const uint8_t *data, unsigned length)
|
||||
{
|
||||
assert(length % BLOCK_SIZE == 0);
|
||||
unsigned blocks = length / BLOCK_SIZE;
|
||||
while (blocks--)
|
||||
{
|
||||
updateOneBlock(data);
|
||||
data += BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
//! It appears that some forms of CBC-MAC encrypt the final output block again in
|
||||
//! order to protect against a plaintext attack. This method is a placeholder for
|
||||
//! such an operation, but it currently does nothing.
|
||||
void RijndaelCBCMAC::finalize()
|
||||
{
|
||||
}
|
||||
|
||||
//! On entry the current value of m_mac becomes the initialization vector
|
||||
//! for the CBC encryption of this block. The output of the encryption then
|
||||
//! becomes the new MAC, which is stored in m_mac.
|
||||
void RijndaelCBCMAC::updateOneBlock(const uint8_t *data)
|
||||
{
|
||||
Rijndael cipher;
|
||||
cipher.init(Rijndael::CBC, Rijndael::Encrypt, m_key, Rijndael::Key16Bytes, m_mac);
|
||||
cipher.blockEncrypt(data, BLOCK_SIZE * 8, m_mac); // size is in bits
|
||||
|
||||
// Log::log(Logger::DEBUG2, "CBC-MAC output block:\n");
|
||||
// logHexArray(Logger::DEBUG2, (const uint8_t *)&m_mac, sizeof(m_mac));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Log an array of bytes as hex.
|
||||
*/
|
||||
void logHexArray(Logger::log_level_t level, const uint8_t *bytes, unsigned count)
|
||||
{
|
||||
Log::SetOutputLevel leveler(level);
|
||||
// Log::log(" ");
|
||||
unsigned i;
|
||||
for (i = 0; i < count; ++i, ++bytes)
|
||||
{
|
||||
if ((i % 16 == 0) && (i < count - 1))
|
||||
{
|
||||
if (i != 0)
|
||||
{
|
||||
Log::log("\n");
|
||||
}
|
||||
Log::log(" 0x%04x: ", i);
|
||||
}
|
||||
Log::log("%02x ", *bytes & 0xff);
|
||||
}
|
||||
|
||||
Log::log("\n");
|
||||
}
|
||||
60
apps/elftosb/common/RijndaelCBCMAC.h
Normal file
60
apps/elftosb/common/RijndaelCBCMAC.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* File: RijndaelCBCMAC.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
#if !defined(_RijndaelCBCMAC_h_)
|
||||
#define _RijndaelCBCMAC_h_
|
||||
|
||||
#include "AESKey.h"
|
||||
#include <string.h>
|
||||
|
||||
/*!
|
||||
* \brief Class to compute CBC-MAC using the AES/Rijndael cipher.
|
||||
*
|
||||
* Currently only supports 128-bit keys and block sizes.
|
||||
*/
|
||||
class RijndaelCBCMAC
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
BLOCK_SIZE = 16 //!< Number of bytes in one cipher block.
|
||||
};
|
||||
|
||||
//! The cipher block data type.
|
||||
typedef uint8_t block_t[BLOCK_SIZE];
|
||||
|
||||
public:
|
||||
//! \brief Default constructor.
|
||||
//!
|
||||
//! The key and IV are both set to zero.
|
||||
RijndaelCBCMAC() {}
|
||||
//! \brief Constructor.
|
||||
RijndaelCBCMAC(const AESKey<128> &key, const uint8_t *iv = 0);
|
||||
|
||||
//! \brief Process data.
|
||||
void update(const uint8_t *data, unsigned length);
|
||||
|
||||
//! \brief Signal that all data has been processed.
|
||||
void finalize();
|
||||
|
||||
//! \brief Returns a reference to the current MAC value.
|
||||
const block_t &getMAC() const { return m_mac; }
|
||||
//! \brief Assignment operator.
|
||||
RijndaelCBCMAC &operator=(const RijndaelCBCMAC &other)
|
||||
{
|
||||
m_key = other.m_key;
|
||||
memcpy(m_mac, other.m_mac, sizeof(m_mac));
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
AESKey<128> m_key; //!< 128-bit key to use for the CBC-MAC.
|
||||
block_t m_mac; //!< Current message authentication code value.
|
||||
|
||||
void updateOneBlock(const uint8_t *data);
|
||||
};
|
||||
|
||||
#endif // _RijndaelCBCMAC_h_
|
||||
77
apps/elftosb/common/RijndaelCTR.cpp
Normal file
77
apps/elftosb/common/RijndaelCTR.cpp
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* File: RijndaelCTR.cpp
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
|
||||
#include "RijndaelCTR.h"
|
||||
#include "rijndael.h"
|
||||
#include <assert.h>
|
||||
#include "Logging.h"
|
||||
|
||||
void logHexArray(Logger::log_level_t level, const uint8_t *bytes, unsigned count);
|
||||
|
||||
//! \param key The key to use
|
||||
//! \param counter The counter to use
|
||||
RijndaelCTR::RijndaelCTR(const AESKey<128> &key, const AESCounter<128> &counter)
|
||||
: m_key(key)
|
||||
, m_counter(counter)
|
||||
{
|
||||
}
|
||||
|
||||
void RijndaelCTR::decrypt(const uint8_t *data, unsigned length, uint8_t *dest)
|
||||
{
|
||||
baseProcess(data, length, dest);
|
||||
}
|
||||
|
||||
void RijndaelCTR::encrypt(const uint8_t *data, unsigned length, uint8_t *dest)
|
||||
{
|
||||
baseProcess(data, length, dest);
|
||||
}
|
||||
|
||||
void RijndaelCTR::baseProcess(const uint8_t *data, unsigned length, uint8_t *dest)
|
||||
{
|
||||
Rijndael cipher;
|
||||
unsigned blocks = length / BLOCK_SIZE;
|
||||
block_t remainder;
|
||||
AESCounter<128>::counter_t currentCounter;
|
||||
|
||||
cipher.init(Rijndael::ECB, Rijndael::Encrypt, m_key, Rijndael::Key16Bytes);
|
||||
|
||||
while (blocks--)
|
||||
{
|
||||
m_counter.getCounter(¤tCounter);
|
||||
|
||||
cipher.blockEncrypt(currentCounter, BLOCK_SIZE * 8, currentCounter);
|
||||
|
||||
for (int i = 0; i < BLOCK_SIZE; i++)
|
||||
{
|
||||
dest[i] = data[i] ^ currentCounter[i];
|
||||
}
|
||||
|
||||
data += BLOCK_SIZE;
|
||||
dest += BLOCK_SIZE;
|
||||
|
||||
m_counter.incrementCounter(BLOCK_SIZE);
|
||||
}
|
||||
|
||||
if (length % sizeof(block_t))
|
||||
{
|
||||
m_counter.getCounter(¤tCounter);
|
||||
|
||||
memset(remainder, 0, sizeof(remainder));
|
||||
memcpy(remainder, data, length % sizeof(block_t));
|
||||
|
||||
cipher.blockEncrypt(currentCounter, BLOCK_SIZE * 8, currentCounter);
|
||||
|
||||
for (unsigned int i = 0; i < length % sizeof(block_t); i++)
|
||||
{
|
||||
remainder[i] = data[i] ^ currentCounter[i];
|
||||
}
|
||||
|
||||
memcpy(dest, remainder, length % sizeof(block_t));
|
||||
|
||||
m_counter.incrementCounter(BLOCK_SIZE);
|
||||
}
|
||||
}
|
||||
60
apps/elftosb/common/RijndaelCTR.h
Normal file
60
apps/elftosb/common/RijndaelCTR.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* File: RijndaelCTR.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
#if !defined(_RijndaelCTR_h_)
|
||||
#define _RijndaelCTR_h_
|
||||
|
||||
#include "AESKey.h"
|
||||
#include "AESCounter.h"
|
||||
#include <string.h>
|
||||
|
||||
/*!
|
||||
* \brief Class to compute AES 128 CTR encryption/decryption.
|
||||
*
|
||||
* Currently only supports 128-bit keys and block sizes.
|
||||
*/
|
||||
class RijndaelCTR
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
BLOCK_SIZE = 16 //!< Number of bytes in one cipher block.
|
||||
};
|
||||
|
||||
//! The cipher block data type.
|
||||
typedef uint8_t block_t[BLOCK_SIZE];
|
||||
|
||||
public:
|
||||
//! \brief Constructor.
|
||||
RijndaelCTR(const AESKey<128> &key, const AESCounter<128> &counter);
|
||||
|
||||
//! \brief Encrypt data.
|
||||
void encrypt(const uint8_t *data, unsigned length, uint8_t *dest);
|
||||
|
||||
//! \brief Encrypt data.
|
||||
void decrypt(const uint8_t *data, unsigned length, uint8_t *dest);
|
||||
|
||||
//! \brief Assignment operator.
|
||||
RijndaelCTR &operator=(const RijndaelCTR &other)
|
||||
{
|
||||
m_key = other.m_key;
|
||||
m_counter = other.m_counter;
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
AESKey<128> m_key; //!< 128-bit key to use for encrypt/decrypt
|
||||
AESCounter<128> m_counter; //!< Counter value for encrypt/decrypt
|
||||
|
||||
void incrementCounter(AESCounter<128>::counter_t *counter);
|
||||
void baseProcess(const uint8_t *data, unsigned length, uint8_t *dest);
|
||||
|
||||
private:
|
||||
//! \brief inaccessible default constructor.
|
||||
RijndaelCTR() {}
|
||||
};
|
||||
|
||||
#endif // _RijndaelCTR_h_
|
||||
361
apps/elftosb/common/SHA1.cpp
Normal file
361
apps/elftosb/common/SHA1.cpp
Normal file
@@ -0,0 +1,361 @@
|
||||
/*
|
||||
100% free public domain implementation of the SHA-1 algorithm
|
||||
by Dominik Reichl <dominik.reichl@t-online.de>
|
||||
Web: http://www.dominik-reichl.de/
|
||||
|
||||
Version 1.6 - 2005-02-07 (thanks to Howard Kapustein for patches)
|
||||
- You can set the endianness in your files, no need to modify the
|
||||
header file of the CSHA1 class any more
|
||||
- Aligned data support
|
||||
- Made support/compilation of the utility functions (ReportHash
|
||||
and HashFile) optional (useful, if bytes count, for example in
|
||||
embedded environments)
|
||||
|
||||
Version 1.5 - 2005-01-01
|
||||
- 64-bit compiler compatibility added
|
||||
- Made variable wiping optional (define SHA1_WIPE_VARIABLES)
|
||||
- Removed unnecessary variable initializations
|
||||
- ROL32 improvement for the Microsoft compiler (using _rotl)
|
||||
|
||||
======== Test Vectors (from FIPS PUB 180-1) ========
|
||||
|
||||
SHA1("abc") =
|
||||
A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
|
||||
|
||||
SHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") =
|
||||
84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
|
||||
|
||||
SHA1(A million repetitions of "a") =
|
||||
34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
|
||||
*/
|
||||
|
||||
#include "SHA1.h"
|
||||
|
||||
#ifdef SHA1_UTILITY_FUNCTIONS
|
||||
#define SHA1_MAX_FILE_BUFFER 8000
|
||||
#endif
|
||||
|
||||
// Rotate x bits to the left
|
||||
#ifndef ROL32
|
||||
#ifdef _MSC_VER
|
||||
#define ROL32(_val32, _nBits) _rotl(_val32, _nBits)
|
||||
#else
|
||||
#define ROL32(_val32, _nBits) (((_val32) << (_nBits)) | ((_val32) >> (32 - (_nBits))))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef SHA1_LITTLE_ENDIAN
|
||||
#define SHABLK0(i) (m_block->l[i] = (ROL32(m_block->l[i], 24) & 0xFF00FF00) | (ROL32(m_block->l[i], 8) & 0x00FF00FF))
|
||||
#else
|
||||
#define SHABLK0(i) (m_block->l[i])
|
||||
#endif
|
||||
|
||||
#define SHABLK(i) \
|
||||
(m_block->l[i & 15] = ROL32( \
|
||||
m_block->l[(i + 13) & 15] ^ m_block->l[(i + 8) & 15] ^ m_block->l[(i + 2) & 15] ^ m_block->l[i & 15], 1))
|
||||
|
||||
// SHA-1 rounds
|
||||
#define _R0(v, w, x, y, z, i) \
|
||||
{ \
|
||||
z += ((w & (x ^ y)) ^ y) + SHABLK0(i) + 0x5A827999 + ROL32(v, 5); \
|
||||
w = ROL32(w, 30); \
|
||||
}
|
||||
#define _R1(v, w, x, y, z, i) \
|
||||
{ \
|
||||
z += ((w & (x ^ y)) ^ y) + SHABLK(i) + 0x5A827999 + ROL32(v, 5); \
|
||||
w = ROL32(w, 30); \
|
||||
}
|
||||
#define _R2(v, w, x, y, z, i) \
|
||||
{ \
|
||||
z += (w ^ x ^ y) + SHABLK(i) + 0x6ED9EBA1 + ROL32(v, 5); \
|
||||
w = ROL32(w, 30); \
|
||||
}
|
||||
#define _R3(v, w, x, y, z, i) \
|
||||
{ \
|
||||
z += (((w | x) & y) | (w & x)) + SHABLK(i) + 0x8F1BBCDC + ROL32(v, 5); \
|
||||
w = ROL32(w, 30); \
|
||||
}
|
||||
#define _R4(v, w, x, y, z, i) \
|
||||
{ \
|
||||
z += (w ^ x ^ y) + SHABLK(i) + 0xCA62C1D6 + ROL32(v, 5); \
|
||||
w = ROL32(w, 30); \
|
||||
}
|
||||
|
||||
CSHA1::CSHA1()
|
||||
{
|
||||
m_block = (SHA1_WORKSPACE_BLOCK *)m_workspace;
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
CSHA1::~CSHA1()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
void CSHA1::Reset()
|
||||
{
|
||||
// SHA1 initialization constants
|
||||
m_state[0] = 0x67452301;
|
||||
m_state[1] = 0xEFCDAB89;
|
||||
m_state[2] = 0x98BADCFE;
|
||||
m_state[3] = 0x10325476;
|
||||
m_state[4] = 0xC3D2E1F0;
|
||||
|
||||
m_count[0] = 0;
|
||||
m_count[1] = 0;
|
||||
}
|
||||
|
||||
void CSHA1::Transform(uint32_t *state, const uint8_t *buffer)
|
||||
{
|
||||
// Copy state[] to working vars
|
||||
uint32_t a = state[0], b = state[1], c = state[2], d = state[3], e = state[4];
|
||||
|
||||
memcpy(m_block, buffer, 64);
|
||||
|
||||
// 4 rounds of 20 operations each. Loop unrolled.
|
||||
_R0(a, b, c, d, e, 0);
|
||||
_R0(e, a, b, c, d, 1);
|
||||
_R0(d, e, a, b, c, 2);
|
||||
_R0(c, d, e, a, b, 3);
|
||||
_R0(b, c, d, e, a, 4);
|
||||
_R0(a, b, c, d, e, 5);
|
||||
_R0(e, a, b, c, d, 6);
|
||||
_R0(d, e, a, b, c, 7);
|
||||
_R0(c, d, e, a, b, 8);
|
||||
_R0(b, c, d, e, a, 9);
|
||||
_R0(a, b, c, d, e, 10);
|
||||
_R0(e, a, b, c, d, 11);
|
||||
_R0(d, e, a, b, c, 12);
|
||||
_R0(c, d, e, a, b, 13);
|
||||
_R0(b, c, d, e, a, 14);
|
||||
_R0(a, b, c, d, e, 15);
|
||||
_R1(e, a, b, c, d, 16);
|
||||
_R1(d, e, a, b, c, 17);
|
||||
_R1(c, d, e, a, b, 18);
|
||||
_R1(b, c, d, e, a, 19);
|
||||
_R2(a, b, c, d, e, 20);
|
||||
_R2(e, a, b, c, d, 21);
|
||||
_R2(d, e, a, b, c, 22);
|
||||
_R2(c, d, e, a, b, 23);
|
||||
_R2(b, c, d, e, a, 24);
|
||||
_R2(a, b, c, d, e, 25);
|
||||
_R2(e, a, b, c, d, 26);
|
||||
_R2(d, e, a, b, c, 27);
|
||||
_R2(c, d, e, a, b, 28);
|
||||
_R2(b, c, d, e, a, 29);
|
||||
_R2(a, b, c, d, e, 30);
|
||||
_R2(e, a, b, c, d, 31);
|
||||
_R2(d, e, a, b, c, 32);
|
||||
_R2(c, d, e, a, b, 33);
|
||||
_R2(b, c, d, e, a, 34);
|
||||
_R2(a, b, c, d, e, 35);
|
||||
_R2(e, a, b, c, d, 36);
|
||||
_R2(d, e, a, b, c, 37);
|
||||
_R2(c, d, e, a, b, 38);
|
||||
_R2(b, c, d, e, a, 39);
|
||||
_R3(a, b, c, d, e, 40);
|
||||
_R3(e, a, b, c, d, 41);
|
||||
_R3(d, e, a, b, c, 42);
|
||||
_R3(c, d, e, a, b, 43);
|
||||
_R3(b, c, d, e, a, 44);
|
||||
_R3(a, b, c, d, e, 45);
|
||||
_R3(e, a, b, c, d, 46);
|
||||
_R3(d, e, a, b, c, 47);
|
||||
_R3(c, d, e, a, b, 48);
|
||||
_R3(b, c, d, e, a, 49);
|
||||
_R3(a, b, c, d, e, 50);
|
||||
_R3(e, a, b, c, d, 51);
|
||||
_R3(d, e, a, b, c, 52);
|
||||
_R3(c, d, e, a, b, 53);
|
||||
_R3(b, c, d, e, a, 54);
|
||||
_R3(a, b, c, d, e, 55);
|
||||
_R3(e, a, b, c, d, 56);
|
||||
_R3(d, e, a, b, c, 57);
|
||||
_R3(c, d, e, a, b, 58);
|
||||
_R3(b, c, d, e, a, 59);
|
||||
_R4(a, b, c, d, e, 60);
|
||||
_R4(e, a, b, c, d, 61);
|
||||
_R4(d, e, a, b, c, 62);
|
||||
_R4(c, d, e, a, b, 63);
|
||||
_R4(b, c, d, e, a, 64);
|
||||
_R4(a, b, c, d, e, 65);
|
||||
_R4(e, a, b, c, d, 66);
|
||||
_R4(d, e, a, b, c, 67);
|
||||
_R4(c, d, e, a, b, 68);
|
||||
_R4(b, c, d, e, a, 69);
|
||||
_R4(a, b, c, d, e, 70);
|
||||
_R4(e, a, b, c, d, 71);
|
||||
_R4(d, e, a, b, c, 72);
|
||||
_R4(c, d, e, a, b, 73);
|
||||
_R4(b, c, d, e, a, 74);
|
||||
_R4(a, b, c, d, e, 75);
|
||||
_R4(e, a, b, c, d, 76);
|
||||
_R4(d, e, a, b, c, 77);
|
||||
_R4(c, d, e, a, b, 78);
|
||||
_R4(b, c, d, e, a, 79);
|
||||
|
||||
// Add the working vars back into state
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
state[4] += e;
|
||||
|
||||
// Wipe variables
|
||||
#ifdef SHA1_WIPE_VARIABLES
|
||||
a = b = c = d = e = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Use this function to hash in binary data and strings
|
||||
void CSHA1::Update(const uint8_t *data, uint32_t len)
|
||||
{
|
||||
uint32_t i, j;
|
||||
|
||||
j = (m_count[0] >> 3) & 63;
|
||||
|
||||
if ((m_count[0] += len << 3) < (len << 3))
|
||||
m_count[1]++;
|
||||
|
||||
m_count[1] += (len >> 29);
|
||||
|
||||
if ((j + len) > 63)
|
||||
{
|
||||
i = 64 - j;
|
||||
memcpy(&m_buffer[j], data, i);
|
||||
Transform(m_state, m_buffer);
|
||||
|
||||
for (; i + 63 < len; i += 64)
|
||||
Transform(m_state, &data[i]);
|
||||
|
||||
j = 0;
|
||||
}
|
||||
else
|
||||
i = 0;
|
||||
|
||||
memcpy(&m_buffer[j], &data[i], len - i);
|
||||
}
|
||||
|
||||
#ifdef SHA1_UTILITY_FUNCTIONS
|
||||
// Hash in file contents
|
||||
bool CSHA1::HashFile(char *szFileName)
|
||||
{
|
||||
unsigned long ulFileSize, ulRest, ulBlocks;
|
||||
unsigned long i;
|
||||
uint8_t uData[SHA1_MAX_FILE_BUFFER];
|
||||
FILE *fIn;
|
||||
|
||||
if (szFileName == NULL)
|
||||
return false;
|
||||
|
||||
fIn = fopen(szFileName, "rb");
|
||||
if (fIn == NULL)
|
||||
return false;
|
||||
|
||||
fseek(fIn, 0, SEEK_END);
|
||||
ulFileSize = (unsigned long)ftell(fIn);
|
||||
fseek(fIn, 0, SEEK_SET);
|
||||
|
||||
if (ulFileSize != 0)
|
||||
{
|
||||
ulBlocks = ulFileSize / SHA1_MAX_FILE_BUFFER;
|
||||
ulRest = ulFileSize % SHA1_MAX_FILE_BUFFER;
|
||||
}
|
||||
else
|
||||
{
|
||||
ulBlocks = 0;
|
||||
ulRest = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < ulBlocks; i++)
|
||||
{
|
||||
fread(uData, 1, SHA1_MAX_FILE_BUFFER, fIn);
|
||||
Update((uint8_t *)uData, SHA1_MAX_FILE_BUFFER);
|
||||
}
|
||||
|
||||
if (ulRest != 0)
|
||||
{
|
||||
fread(uData, 1, ulRest, fIn);
|
||||
Update((uint8_t *)uData, ulRest);
|
||||
}
|
||||
|
||||
fclose(fIn);
|
||||
fIn = NULL;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void CSHA1::Final()
|
||||
{
|
||||
uint32_t i;
|
||||
uint8_t finalcount[8];
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
finalcount[i] = (uint8_t)((m_count[((i >= 4) ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255); // Endian independent
|
||||
|
||||
Update((uint8_t *)"\200", 1);
|
||||
|
||||
while ((m_count[0] & 504) != 448)
|
||||
Update((uint8_t *)"\0", 1);
|
||||
|
||||
Update(finalcount, 8); // Cause a SHA1Transform()
|
||||
|
||||
for (i = 0; i < 20; i++)
|
||||
{
|
||||
m_digest[i] = (uint8_t)((m_state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
|
||||
}
|
||||
|
||||
// Wipe variables for security reasons
|
||||
#ifdef SHA1_WIPE_VARIABLES
|
||||
i = 0;
|
||||
memset(m_buffer, 0, 64);
|
||||
memset(m_state, 0, 20);
|
||||
memset(m_count, 0, 8);
|
||||
memset(finalcount, 0, 8);
|
||||
Transform(m_state, m_buffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef SHA1_UTILITY_FUNCTIONS
|
||||
// Get the final hash as a pre-formatted string
|
||||
void CSHA1::ReportHash(char *szReport, unsigned char uReportType)
|
||||
{
|
||||
unsigned char i;
|
||||
char szTemp[16];
|
||||
|
||||
if (szReport == NULL)
|
||||
return;
|
||||
|
||||
if (uReportType == REPORT_HEX)
|
||||
{
|
||||
sprintf(szTemp, "%02X", m_digest[0]);
|
||||
strcat(szReport, szTemp);
|
||||
|
||||
for (i = 1; i < 20; i++)
|
||||
{
|
||||
sprintf(szTemp, " %02X", m_digest[i]);
|
||||
strcat(szReport, szTemp);
|
||||
}
|
||||
}
|
||||
else if (uReportType == REPORT_DIGIT)
|
||||
{
|
||||
sprintf(szTemp, "%u", m_digest[0]);
|
||||
strcat(szReport, szTemp);
|
||||
|
||||
for (i = 1; i < 20; i++)
|
||||
{
|
||||
sprintf(szTemp, " %u", m_digest[i]);
|
||||
strcat(szReport, szTemp);
|
||||
}
|
||||
}
|
||||
else
|
||||
strcpy(szReport, "Error: Unknown report type!");
|
||||
}
|
||||
#endif
|
||||
|
||||
// Get the raw message digest
|
||||
void CSHA1::GetHash(uint8_t *puDest)
|
||||
{
|
||||
memcpy(puDest, m_digest, 20);
|
||||
}
|
||||
149
apps/elftosb/common/SHA1.h
Normal file
149
apps/elftosb/common/SHA1.h
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
100% free public domain implementation of the SHA-1 algorithm
|
||||
by Dominik Reichl <dominik.reichl@t-online.de>
|
||||
Web: http://www.dominik-reichl.de/
|
||||
|
||||
Version 1.6 - 2005-02-07 (thanks to Howard Kapustein for patches)
|
||||
- You can set the endianness in your files, no need to modify the
|
||||
header file of the CSHA1 class any more
|
||||
- Aligned data support
|
||||
- Made support/compilation of the utility functions (ReportHash
|
||||
and HashFile) optional (useful, if bytes count, for example in
|
||||
embedded environments)
|
||||
|
||||
Version 1.5 - 2005-01-01
|
||||
- 64-bit compiler compatibility added
|
||||
- Made variable wiping optional (define SHA1_WIPE_VARIABLES)
|
||||
- Removed unnecessary variable initializations
|
||||
- ROL32 improvement for the Microsoft compiler (using _rotl)
|
||||
|
||||
======== Test Vectors (from FIPS PUB 180-1) ========
|
||||
|
||||
SHA1("abc") =
|
||||
A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
|
||||
|
||||
SHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") =
|
||||
84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
|
||||
|
||||
SHA1(A million repetitions of "a") =
|
||||
34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
|
||||
*/
|
||||
|
||||
#ifndef ___SHA1_HDR___
|
||||
#define ___SHA1_HDR___
|
||||
|
||||
#if !defined(SHA1_UTILITY_FUNCTIONS) && !defined(SHA1_NO_UTILITY_FUNCTIONS)
|
||||
#define SHA1_UTILITY_FUNCTIONS
|
||||
#endif
|
||||
|
||||
#include <memory.h> // Needed for memset and memcpy
|
||||
#include "stdafx.h"
|
||||
|
||||
#ifdef SHA1_UTILITY_FUNCTIONS
|
||||
#include <stdio.h> // Needed for file access and sprintf
|
||||
#include <string.h> // Needed for strcat and strcpy
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
// You can define the endian mode in your files, without modifying the SHA1
|
||||
// source files. Just #define SHA1_LITTLE_ENDIAN or #define SHA1_BIG_ENDIAN
|
||||
// in your files, before including the SHA1.h header file. If you don't
|
||||
// define anything, the class defaults to little endian.
|
||||
|
||||
#if !defined(SHA1_LITTLE_ENDIAN) && !defined(SHA1_BIG_ENDIAN)
|
||||
#define SHA1_LITTLE_ENDIAN
|
||||
#endif
|
||||
|
||||
// Same here. If you want variable wiping, #define SHA1_WIPE_VARIABLES, if
|
||||
// not, #define SHA1_NO_WIPE_VARIABLES. If you don't define anything, it
|
||||
// defaults to wiping.
|
||||
|
||||
#if !defined(SHA1_WIPE_VARIABLES) && !defined(SHA1_NO_WIPE_VARIABLES)
|
||||
#define SHA1_WIPE_VARIABLES
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Define 8- and 32-bit variables
|
||||
|
||||
//#ifndef uint32_t
|
||||
//
|
||||
//#ifdef _MSC_VER
|
||||
//
|
||||
//#define uint8_t unsigned __int8
|
||||
//#define uint32_t unsigned __int32
|
||||
//
|
||||
//#else
|
||||
//
|
||||
//#define uint8_t unsigned char
|
||||
//
|
||||
//#if (ULONG_MAX == 0xFFFFFFFF)
|
||||
//#define uint32_t unsigned long
|
||||
//#else
|
||||
//#define uint32_t unsigned int
|
||||
//#endif
|
||||
//
|
||||
//#endif
|
||||
//#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Declare SHA1 workspace
|
||||
|
||||
typedef union
|
||||
{
|
||||
uint8_t c[64];
|
||||
uint32_t l[16];
|
||||
} SHA1_WORKSPACE_BLOCK;
|
||||
|
||||
class CSHA1
|
||||
{
|
||||
public:
|
||||
#ifdef SHA1_UTILITY_FUNCTIONS
|
||||
// Two different formats for ReportHash(...)
|
||||
enum
|
||||
{
|
||||
REPORT_HEX = 0,
|
||||
REPORT_DIGIT = 1
|
||||
};
|
||||
#endif
|
||||
|
||||
// Constructor and Destructor
|
||||
CSHA1();
|
||||
~CSHA1();
|
||||
|
||||
uint32_t m_state[5];
|
||||
uint32_t m_count[2];
|
||||
uint32_t __reserved1[1];
|
||||
uint8_t m_buffer[64];
|
||||
uint8_t m_digest[20];
|
||||
uint32_t __reserved2[3];
|
||||
|
||||
void Reset();
|
||||
|
||||
// Update the hash value
|
||||
void Update(const uint8_t *data, uint32_t len);
|
||||
#ifdef SHA1_UTILITY_FUNCTIONS
|
||||
bool HashFile(char *szFileName);
|
||||
#endif
|
||||
|
||||
// Finalize hash and report
|
||||
void Final();
|
||||
|
||||
// Report functions: as pre-formatted and raw data
|
||||
#ifdef SHA1_UTILITY_FUNCTIONS
|
||||
void ReportHash(char *szReport, unsigned char uReportType = REPORT_HEX);
|
||||
#endif
|
||||
void GetHash(uint8_t *puDest);
|
||||
|
||||
private:
|
||||
// Private SHA-1 transformation
|
||||
void Transform(uint32_t *state, const uint8_t *buffer);
|
||||
|
||||
// Member variables
|
||||
uint8_t m_workspace[64];
|
||||
SHA1_WORKSPACE_BLOCK *m_block; // SHA1 pointer to the byte array above
|
||||
};
|
||||
|
||||
#endif
|
||||
178
apps/elftosb/common/SRecordSourceFile.cpp
Normal file
178
apps/elftosb/common/SRecordSourceFile.cpp
Normal file
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* File: SRecordSourceFile.cpp
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
|
||||
#include "SRecordSourceFile.h"
|
||||
#include "Logging.h"
|
||||
#include "smart_ptr.h"
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
enum
|
||||
{
|
||||
//! Size in bytes of the buffer used to collect S-record data records
|
||||
//! before adding them to the executable image. Currently 64KB.
|
||||
COLLECTION_BUFFER_SIZE = 64 * 1024
|
||||
};
|
||||
|
||||
using namespace elftosb;
|
||||
|
||||
SRecordSourceFile::SRecordSourceFile(const std::string &path)
|
||||
: SourceFile(path)
|
||||
, m_image(0)
|
||||
, m_hasEntryRecord(false)
|
||||
{
|
||||
}
|
||||
|
||||
bool SRecordSourceFile::isSRecordFile(std::istream &stream)
|
||||
{
|
||||
StSRecordFile srec(stream);
|
||||
return srec.isSRecordFile();
|
||||
}
|
||||
|
||||
void SRecordSourceFile::open()
|
||||
{
|
||||
SourceFile::open();
|
||||
|
||||
// create file parser and examine file
|
||||
m_file = new StSRecordFile(*m_stream);
|
||||
m_file->parse();
|
||||
|
||||
// build an image of the file
|
||||
m_image = new StExecutableImage();
|
||||
buildMemoryImage();
|
||||
|
||||
// dispose of file parser object
|
||||
delete m_file;
|
||||
m_file = 0;
|
||||
}
|
||||
|
||||
void SRecordSourceFile::close()
|
||||
{
|
||||
assert(m_image);
|
||||
|
||||
SourceFile::close();
|
||||
|
||||
// dispose of memory image
|
||||
delete m_image;
|
||||
m_image = 0;
|
||||
}
|
||||
|
||||
//! \pre The file must be open before this method can be called.
|
||||
//!
|
||||
DataSource *SRecordSourceFile::createDataSource()
|
||||
{
|
||||
assert(m_image);
|
||||
return new MemoryImageDataSource(m_image);
|
||||
}
|
||||
|
||||
//! \retval true The file has an S7, S8, or S9 record.
|
||||
//! \retval false No entry point is available.
|
||||
bool SRecordSourceFile::hasEntryPoint()
|
||||
{
|
||||
return m_hasEntryRecord;
|
||||
}
|
||||
|
||||
//! If no entry point is available then 0 is returned instead. The method scans
|
||||
//! the records in the file looking for S7, S8, or S9 records. Thus, 16-bit,
|
||||
//! 24-bit, and 32-bit entry point records are supported.
|
||||
//!
|
||||
//! \return Entry point address.
|
||||
//! \retval 0 No entry point is available.
|
||||
uint32_t SRecordSourceFile::getEntryPointAddress()
|
||||
{
|
||||
if (m_hasEntryRecord)
|
||||
{
|
||||
// the address in the record is the entry point
|
||||
Log::log(Logger::DEBUG2, "entry point address is 0x%08x\n", m_entryRecord.m_address);
|
||||
return m_entryRecord.m_address;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//! Scans the S-records of the file looking for data records. These are S3, S2, or
|
||||
//! S1 records. The contents of these records are added to an StExecutableImage
|
||||
//! object, which coalesces the individual records into contiguous regions of
|
||||
//! memory.
|
||||
//!
|
||||
//! Also looks for S7, S8, or S9 records that contain the entry point. The first
|
||||
//! match of one of these records is saved off into the #m_entryRecord member.
|
||||
//!
|
||||
//! \pre The #m_file member must be valid.
|
||||
//! \pre The #m_image member variable must have been instantiated.
|
||||
void SRecordSourceFile::buildMemoryImage()
|
||||
{
|
||||
assert(m_file);
|
||||
assert(m_image);
|
||||
|
||||
// Clear the entry point related members.
|
||||
m_hasEntryRecord = false;
|
||||
memset(&m_entryRecord, 0, sizeof(m_entryRecord));
|
||||
|
||||
// Allocate buffer to hold data before adding it to the executable image.
|
||||
// Contiguous records are added to this buffer. When overflowed or when a
|
||||
// non-contiguous record is encountered the buffer is added to the executable
|
||||
// image where it will be coalesced further. We don't add records individually
|
||||
// to the image because coalescing record by record is very slow.
|
||||
smart_array_ptr<uint8_t> buffer = new uint8_t[COLLECTION_BUFFER_SIZE];
|
||||
unsigned startAddress;
|
||||
unsigned nextAddress;
|
||||
unsigned dataLength = 0;
|
||||
|
||||
// process SRecords
|
||||
StSRecordFile::const_iterator it = m_file->getBegin();
|
||||
for (; it != m_file->getEnd(); it++)
|
||||
{
|
||||
const StSRecordFile::SRecord &theRecord = *it;
|
||||
|
||||
// only handle S3,2,1 records
|
||||
bool isDataRecord = theRecord.m_type == 3 || theRecord.m_type == 2 || theRecord.m_type == 1;
|
||||
bool hasData = theRecord.m_data && theRecord.m_dataCount;
|
||||
if (isDataRecord && hasData)
|
||||
{
|
||||
// If this record's data would overflow the collection buffer, or if the
|
||||
// record is not contiguous with the rest of the data in the collection
|
||||
// buffer, then flush the buffer to the executable image and restart.
|
||||
if (dataLength &&
|
||||
((dataLength + theRecord.m_dataCount > COLLECTION_BUFFER_SIZE) || (theRecord.m_address != nextAddress)))
|
||||
{
|
||||
m_image->addTextRegion(startAddress, buffer, dataLength);
|
||||
|
||||
dataLength = 0;
|
||||
}
|
||||
|
||||
// Capture addresses when starting an empty buffer.
|
||||
if (dataLength == 0)
|
||||
{
|
||||
startAddress = theRecord.m_address;
|
||||
nextAddress = startAddress;
|
||||
}
|
||||
|
||||
// Copy record data into place in the collection buffer and update
|
||||
// size and address.
|
||||
memcpy(&buffer[dataLength], theRecord.m_data, theRecord.m_dataCount);
|
||||
dataLength += theRecord.m_dataCount;
|
||||
nextAddress += theRecord.m_dataCount;
|
||||
}
|
||||
else if (!m_hasEntryRecord)
|
||||
{
|
||||
// look for S7,8,9 records
|
||||
bool isEntryPointRecord = theRecord.m_type == 7 || theRecord.m_type == 8 || theRecord.m_type == 9;
|
||||
if (isEntryPointRecord)
|
||||
{
|
||||
// save off the entry point record so we don't have to scan again
|
||||
memcpy(&m_entryRecord, &theRecord, sizeof(m_entryRecord));
|
||||
m_hasEntryRecord = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add any leftover data in the collection buffer to the executable image.
|
||||
if (dataLength)
|
||||
{
|
||||
m_image->addTextRegion(startAddress, buffer, dataLength);
|
||||
}
|
||||
}
|
||||
81
apps/elftosb/common/SRecordSourceFile.h
Normal file
81
apps/elftosb/common/SRecordSourceFile.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* File: SRecordSourceFile.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
#if !defined(_SRecordSourceFile_h_)
|
||||
#define _SRecordSourceFile_h_
|
||||
|
||||
#include "SourceFile.h"
|
||||
#include "StSRecordFile.h"
|
||||
#include "StExecutableImage.h"
|
||||
|
||||
namespace elftosb
|
||||
{
|
||||
/*!
|
||||
* \brief Executable file in the Motorola S-record format.
|
||||
*
|
||||
* Instead of presenting each S-record in the file separately, this class
|
||||
* builds up a memory image of all of the records. Records next to each other
|
||||
* in memory are coalesced into a single memory region. The data source that
|
||||
* is returned from createDataSource() exposes these regions as its segments.
|
||||
*
|
||||
* Because the S-record format does not support the concepts, no support is
|
||||
* provided for named sections or symbols.
|
||||
*/
|
||||
class SRecordSourceFile : public SourceFile
|
||||
{
|
||||
public:
|
||||
//! \brief Default constructor.
|
||||
SRecordSourceFile(const std::string &path);
|
||||
|
||||
//! \brief Destructor.
|
||||
virtual ~SRecordSourceFile() {}
|
||||
//! \brief Test whether the \a stream contains a valid S-record file.
|
||||
static bool isSRecordFile(std::istream &stream);
|
||||
|
||||
//! \name Opening and closing
|
||||
//@{
|
||||
//! \brief Opens the file.
|
||||
virtual void open();
|
||||
|
||||
//! \brief Closes the file.
|
||||
virtual void close();
|
||||
//@}
|
||||
|
||||
//! \name Format capabilities
|
||||
//@{
|
||||
virtual bool supportsNamedSections() const { return false; }
|
||||
virtual bool supportsNamedSymbols() const { return false; }
|
||||
//@}
|
||||
|
||||
//! \name Data sources
|
||||
//@{
|
||||
//! \brief Returns data source for the entire file.
|
||||
virtual DataSource *createDataSource();
|
||||
//@}
|
||||
|
||||
//! \name Entry point
|
||||
//@{
|
||||
//! \brief Returns true if an entry point was set in the file.
|
||||
virtual bool hasEntryPoint();
|
||||
|
||||
//! \brief Returns the entry point address.
|
||||
virtual uint32_t getEntryPointAddress();
|
||||
//@}
|
||||
|
||||
protected:
|
||||
StSRecordFile *m_file; //!< S-record parser instance.
|
||||
StExecutableImage *m_image; //!< Memory image of the S-record file.
|
||||
bool m_hasEntryRecord; //!< Whether an S7,8,9 record was found.
|
||||
StSRecordFile::SRecord m_entryRecord; //!< Record for the entry point.
|
||||
|
||||
protected:
|
||||
//! \brief Build memory image of the S-record file.
|
||||
void buildMemoryImage();
|
||||
};
|
||||
|
||||
}; // namespace elftosb
|
||||
|
||||
#endif // _SRecordSourceFile_h_
|
||||
121
apps/elftosb/common/SearchPath.cpp
Normal file
121
apps/elftosb/common/SearchPath.cpp
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* File: SearchPath.cpp
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
|
||||
#include "SearchPath.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined(WIN32)
|
||||
#define PATH_SEP_CHAR '\\'
|
||||
#define PATH_SEP_STRING "\\"
|
||||
#else
|
||||
#define PATH_SEP_CHAR '/'
|
||||
#define PATH_SEP_STRING "/"
|
||||
#endif
|
||||
|
||||
PathSearcher *PathSearcher::s_searcher = NULL;
|
||||
|
||||
//! This function will create the global path search object if it has
|
||||
//! not already been created.
|
||||
PathSearcher &PathSearcher::getGlobalSearcher()
|
||||
{
|
||||
if (!s_searcher)
|
||||
{
|
||||
s_searcher = new PathSearcher;
|
||||
}
|
||||
|
||||
return *s_searcher;
|
||||
}
|
||||
|
||||
void PathSearcher::addSearchPath(std::string &path)
|
||||
{
|
||||
m_paths.push_back(path);
|
||||
}
|
||||
|
||||
//! The \a base path argument can be either a relative or absolute path. If the path
|
||||
//! is relative, then it is joined with search paths one after another until a matching
|
||||
//! file is located or all search paths are exhausted. If the \a base is absolute,
|
||||
//! only that path is tested and if invalid false is returned.
|
||||
//!
|
||||
//! \param base A path to the file that is to be found.
|
||||
//! \param targetType Currently ignored. In the future it will let you select whether to
|
||||
//! find a file or directory.
|
||||
//! \param searchCwd If set to true, the current working directory is searched before using
|
||||
//! any of the search paths. Otherwise only the search paths are considered.
|
||||
//! \param[out] result When true is returned this string is set to the first path at which
|
||||
//! a valid file was found.
|
||||
//!
|
||||
//! \retval true A matching file was found among the search paths. The contents of \a result
|
||||
//! are a valid path.
|
||||
//! \retval false No match could be made. \a result has been left unmodified.
|
||||
bool PathSearcher::search(const std::string &base, target_type_t targetType, bool searchCwd, std::string &result)
|
||||
{
|
||||
FILE *tempFile;
|
||||
bool absolute = isAbsolute(base);
|
||||
|
||||
// Try cwd first if requested. Same process applies to absolute paths.
|
||||
if (absolute || searchCwd)
|
||||
{
|
||||
tempFile = fopen(base.c_str(), "r");
|
||||
if (tempFile)
|
||||
{
|
||||
fclose(tempFile);
|
||||
result = base;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// If the base path is absolute and the previous test failed, then we don't go any further.
|
||||
if (absolute)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Iterate over all search paths.
|
||||
string_list_t::const_iterator it = m_paths.begin();
|
||||
for (; it != m_paths.end(); ++it)
|
||||
{
|
||||
std::string searchPath = joinPaths(*it, base);
|
||||
|
||||
tempFile = fopen(searchPath.c_str(), "r");
|
||||
if (tempFile)
|
||||
{
|
||||
fclose(tempFile);
|
||||
result = searchPath;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Couldn't find anything matching the base path.
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PathSearcher::isAbsolute(const std::string &path)
|
||||
{
|
||||
#if __WIN32__
|
||||
return path.size() >= 3 && path[1] == ':' && path[2] == '\\';
|
||||
#else
|
||||
return path.size() >= 1 && path[0] == '/';
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string PathSearcher::joinPaths(const std::string &first, const std::string &second)
|
||||
{
|
||||
// Start with first string.
|
||||
std::string result = first;
|
||||
|
||||
// Add path separator if needed
|
||||
if ((first[first.size() - 1] != PATH_SEP_CHAR) && (second[0] != PATH_SEP_CHAR))
|
||||
{
|
||||
result += PATH_SEP_STRING;
|
||||
}
|
||||
|
||||
// Append the second string.
|
||||
result += second;
|
||||
|
||||
// And return the whole mess.
|
||||
return result;
|
||||
}
|
||||
57
apps/elftosb/common/SearchPath.h
Normal file
57
apps/elftosb/common/SearchPath.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* File: SearchPath.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
#if !defined(_searchpath_h_)
|
||||
#define _searchpath_h_
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
/*!
|
||||
* \brief Handles searching a list of paths for a file.
|
||||
*/
|
||||
class PathSearcher
|
||||
{
|
||||
public:
|
||||
//!
|
||||
enum _target_type
|
||||
{
|
||||
kFindFile,
|
||||
kFindDirectory
|
||||
};
|
||||
|
||||
//!
|
||||
typedef enum _target_type target_type_t;
|
||||
|
||||
protected:
|
||||
//! Global search object singleton.
|
||||
static PathSearcher *s_searcher;
|
||||
|
||||
public:
|
||||
//! \brief Access global path searching object.
|
||||
static PathSearcher &getGlobalSearcher();
|
||||
|
||||
public:
|
||||
//! \brief Constructor.
|
||||
PathSearcher() {}
|
||||
//! \brief Add a new search path to the end of the list.
|
||||
void addSearchPath(std::string &path);
|
||||
|
||||
//! \brief Attempts to locate a file by using the search paths.
|
||||
bool search(const std::string &base, target_type_t targetType, bool searchCwd, std::string &result);
|
||||
|
||||
protected:
|
||||
typedef std::list<std::string> string_list_t; //!< Linked list of strings.
|
||||
string_list_t m_paths; //!< Ordered list of paths to search.
|
||||
|
||||
//! \brief Returns whether \a path is absolute.
|
||||
bool isAbsolute(const std::string &path);
|
||||
|
||||
//! \brief Combines two paths into a single one.
|
||||
std::string joinPaths(const std::string &first, const std::string &second);
|
||||
};
|
||||
|
||||
#endif // _searchpath_h_
|
||||
179
apps/elftosb/common/SourceFile.cpp
Normal file
179
apps/elftosb/common/SourceFile.cpp
Normal file
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* File: SourceFile.cpp
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
|
||||
#include "SourceFile.h"
|
||||
#include "ELFSourceFile.h"
|
||||
#include "SRecordSourceFile.h"
|
||||
#include <assert.h>
|
||||
#include "format_string.h"
|
||||
#include "SearchPath.h"
|
||||
|
||||
using namespace elftosb;
|
||||
|
||||
//! The supported file types are currently:
|
||||
//! - ELF files
|
||||
//! - Motorola S-record files
|
||||
//! - Binary files
|
||||
//!
|
||||
//! Any file that is not picked up by the other subclasses will result in a
|
||||
//! an instance of BinaryDataFile.
|
||||
//!
|
||||
//! \return An instance of the correct subclass of SourceFile for the given path.
|
||||
//!
|
||||
//! \exception std::runtime_error Thrown if the file cannot be opened.
|
||||
//!
|
||||
//! \see elftosb::ELFSourceFile
|
||||
//! \see elftosb::SRecordSourceFile
|
||||
//! \see elftosb::BinarySourceFile
|
||||
SourceFile *SourceFile::openFile(const std::string &path)
|
||||
{
|
||||
// Search for file using search paths
|
||||
std::string actualPath;
|
||||
bool found = PathSearcher::getGlobalSearcher().search(path, PathSearcher::kFindFile, true, actualPath);
|
||||
if (!found)
|
||||
{
|
||||
throw std::runtime_error(format_string("unable to find file %s\n", path.c_str()));
|
||||
}
|
||||
|
||||
std::ifstream testStream(actualPath.c_str(), std::ios_base::in | std::ios_base::binary);
|
||||
if (!testStream.is_open())
|
||||
{
|
||||
throw std::runtime_error(format_string("failed to open file: %s", actualPath.c_str()));
|
||||
}
|
||||
|
||||
// catch exceptions so we can close the file stream
|
||||
try
|
||||
{
|
||||
if (ELFSourceFile::isELFFile(testStream))
|
||||
{
|
||||
testStream.close();
|
||||
return new ELFSourceFile(actualPath);
|
||||
}
|
||||
else if (SRecordSourceFile::isSRecordFile(testStream))
|
||||
{
|
||||
testStream.close();
|
||||
return new SRecordSourceFile(actualPath);
|
||||
}
|
||||
|
||||
// treat it as a binary file
|
||||
testStream.close();
|
||||
return new BinarySourceFile(actualPath);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
testStream.close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
SourceFile::SourceFile(const std::string &path)
|
||||
: m_path(path)
|
||||
, m_stream()
|
||||
{
|
||||
}
|
||||
|
||||
//! The file is closed if it had been left opened.
|
||||
//!
|
||||
SourceFile::~SourceFile()
|
||||
{
|
||||
if (isOpen())
|
||||
{
|
||||
m_stream->close();
|
||||
}
|
||||
}
|
||||
|
||||
//! \exception std::runtime_error Raised if the file could not be opened successfully.
|
||||
void SourceFile::open()
|
||||
{
|
||||
assert(!isOpen());
|
||||
m_stream = new std::ifstream(m_path.c_str(), std::ios_base::in | std::ios_base::binary);
|
||||
if (!m_stream->is_open())
|
||||
{
|
||||
throw std::runtime_error(format_string("failed to open file: %s", m_path.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
void SourceFile::close()
|
||||
{
|
||||
assert(isOpen());
|
||||
|
||||
m_stream->close();
|
||||
m_stream.safe_delete();
|
||||
}
|
||||
|
||||
unsigned SourceFile::getSize()
|
||||
{
|
||||
bool wasOpen = isOpen();
|
||||
std::ifstream::pos_type oldPosition;
|
||||
|
||||
if (!wasOpen)
|
||||
{
|
||||
open();
|
||||
}
|
||||
|
||||
assert(m_stream);
|
||||
oldPosition = m_stream->tellg();
|
||||
m_stream->seekg(0, std::ios_base::end);
|
||||
unsigned resultSize = static_cast<unsigned>(m_stream->tellg());
|
||||
m_stream->seekg(oldPosition);
|
||||
|
||||
if (!wasOpen)
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
return resultSize;
|
||||
}
|
||||
|
||||
//! If the file does not support named sections, or if there is not a
|
||||
//! section with the given name, this method may return NULL.
|
||||
//!
|
||||
//! This method is just a small wrapper that creates an
|
||||
//! FixedMatcher string matcher instance and uses the createDataSource()
|
||||
//! that takes a reference to a StringMatcher.
|
||||
DataSource *SourceFile::createDataSource(const std::string §ion)
|
||||
{
|
||||
FixedMatcher matcher(section);
|
||||
return createDataSource(matcher);
|
||||
}
|
||||
|
||||
DataTarget *SourceFile::createDataTargetForEntryPoint()
|
||||
{
|
||||
if (!hasEntryPoint())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return new ConstantDataTarget(getEntryPointAddress());
|
||||
}
|
||||
|
||||
DataSource *BinarySourceFile::createDataSource()
|
||||
{
|
||||
std::istream *fileStream = getStream();
|
||||
assert(fileStream);
|
||||
|
||||
// get stream size
|
||||
fileStream->seekg(0, std::ios_base::end);
|
||||
int length = static_cast<int>(fileStream->tellg());
|
||||
|
||||
// allocate buffer
|
||||
smart_array_ptr<uint8_t> data = new uint8_t[length];
|
||||
// if (!data)
|
||||
// {
|
||||
// throw std::bad_alloc();
|
||||
// }
|
||||
|
||||
// read entire file into the buffer
|
||||
fileStream->seekg(0, std::ios_base::beg);
|
||||
if (fileStream->read((char *)data.get(), length).bad())
|
||||
{
|
||||
throw std::runtime_error(format_string("unexpected end of file: %s", m_path.c_str()));
|
||||
}
|
||||
|
||||
// create the data source. the buffer is copied, so we can dispose of it.
|
||||
return new UnmappedDataSource(data, length);
|
||||
}
|
||||
152
apps/elftosb/common/SourceFile.h
Normal file
152
apps/elftosb/common/SourceFile.h
Normal file
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* File: SourceFile.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
#if !defined(_SourceFile_h_)
|
||||
#define _SourceFile_h_
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include "smart_ptr.h"
|
||||
#include "DataSource.h"
|
||||
#include "DataTarget.h"
|
||||
#include "StringMatcher.h"
|
||||
#include "OptionContext.h"
|
||||
|
||||
namespace elftosb
|
||||
{
|
||||
/*!
|
||||
* \brief Abstract base class for a source file containing executable code.
|
||||
*
|
||||
* The purpose of this class cluster is to provide a common interface for
|
||||
* accessing the contents of different file formats. This is accomplished
|
||||
* through several small sets of methods along with the DataSource and
|
||||
* DataTarget classes.
|
||||
*
|
||||
* The primary interface for creating instances of SourceFile is the static
|
||||
* SourceFile::openFile() function. It will create the correct subclass of
|
||||
* SourceFile by inspecting the file to determine its type.
|
||||
*/
|
||||
class SourceFile
|
||||
{
|
||||
public:
|
||||
// \brief Factory function that creates the correct subclass of SourceFile.
|
||||
static SourceFile *openFile(const std::string &path);
|
||||
|
||||
public:
|
||||
//! \brief Default constructor.
|
||||
SourceFile(const std::string &path);
|
||||
|
||||
//! \brief Destructor.
|
||||
virtual ~SourceFile();
|
||||
|
||||
//! \brief Set the option context.
|
||||
//!
|
||||
//! The source file will take ownership of the @a context and delete it
|
||||
//! when the source file is itself deleted.
|
||||
inline void setOptions(OptionContext *context) { m_options = context; }
|
||||
//! \brief Return the option context.
|
||||
inline const OptionContext *getOptions() const { return m_options; }
|
||||
//! \brief Returns the path to the file.
|
||||
inline const std::string &getPath() const { return m_path; }
|
||||
//! \brief Get the size in bytes of the file.
|
||||
unsigned getSize();
|
||||
|
||||
//! \name Opening and closing
|
||||
//@{
|
||||
//! \brief Opens the file.
|
||||
virtual void open();
|
||||
|
||||
//! \brief Closes the file.
|
||||
virtual void close();
|
||||
|
||||
//! \brief Returns whether the file is already open.
|
||||
virtual bool isOpen() const { return (bool)m_stream && const_cast<std::ifstream *>(m_stream.get())->is_open(); }
|
||||
//@}
|
||||
|
||||
//! \name Format capabilities
|
||||
//@{
|
||||
virtual bool supportsNamedSections() const = 0;
|
||||
virtual bool supportsNamedSymbols() const = 0;
|
||||
//@}
|
||||
|
||||
//! \name Data source creation
|
||||
//@{
|
||||
//! \brief Creates a data source from the entire file.
|
||||
virtual DataSource *createDataSource() = 0;
|
||||
|
||||
//! \brief Creates a data source out of one or more sections of the file.
|
||||
//!
|
||||
//! The \a selector object is used to perform the section name comparison.
|
||||
//! If the file does not support named sections, or if there is not a
|
||||
//! section with the given name, this method may return NULL.
|
||||
virtual DataSource *createDataSource(StringMatcher &matcher) { return NULL; }
|
||||
//! \brief Creates a data source out of one section of the file.
|
||||
virtual DataSource *createDataSource(const std::string §ion);
|
||||
//@}
|
||||
|
||||
//! \name Entry point
|
||||
//@{
|
||||
//! \brief Returns true if an entry point was set in the file.
|
||||
virtual bool hasEntryPoint() = 0;
|
||||
|
||||
//! \brief Returns the entry point address.
|
||||
virtual uint32_t getEntryPointAddress() { return 0; }
|
||||
//@}
|
||||
|
||||
//! \name Data target creation
|
||||
//@{
|
||||
virtual DataTarget *createDataTargetForSection(const std::string §ion) { return NULL; }
|
||||
virtual DataTarget *createDataTargetForSymbol(const std::string &symbol) { return NULL; }
|
||||
virtual DataTarget *createDataTargetForEntryPoint();
|
||||
//@}
|
||||
|
||||
//! \name Symbols
|
||||
//@{
|
||||
//! \brief Returns whether a symbol exists in the source file.
|
||||
virtual bool hasSymbol(const std::string &name) { return false; }
|
||||
//! \brief Returns the value of a symbol.
|
||||
virtual uint32_t getSymbolValue(const std::string &name) { return 0; }
|
||||
//! \brief Returns the size of a symbol.
|
||||
virtual unsigned getSymbolSize(const std::string &name) { return 0; }
|
||||
//@}
|
||||
|
||||
protected:
|
||||
std::string m_path; //!< Path to the file.
|
||||
smart_ptr<std::ifstream> m_stream; //!< File stream, or NULL if file is closed.
|
||||
smart_ptr<OptionContext> m_options; //!< Table of option values.
|
||||
|
||||
//! \brief Internal access to the input stream object.
|
||||
inline std::ifstream *getStream() { return m_stream; }
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Binary data file.
|
||||
*/
|
||||
class BinarySourceFile : public SourceFile
|
||||
{
|
||||
public:
|
||||
//! \brief Default constructor.
|
||||
BinarySourceFile(const std::string &path)
|
||||
: SourceFile(path)
|
||||
{
|
||||
}
|
||||
|
||||
//! \name Format capabilities
|
||||
//@{
|
||||
virtual bool supportsNamedSections() const { return false; }
|
||||
virtual bool supportsNamedSymbols() const { return false; }
|
||||
//@}
|
||||
|
||||
//! \brief Creates an unmapped data source from the entire file.
|
||||
virtual DataSource *createDataSource();
|
||||
|
||||
virtual bool hasEntryPoint() { return false; }
|
||||
};
|
||||
|
||||
}; // namespace elftosb
|
||||
|
||||
#endif // _SourceFile_h_
|
||||
533
apps/elftosb/common/StELFFile.cpp
Normal file
533
apps/elftosb/common/StELFFile.cpp
Normal file
File diff suppressed because it is too large
Load Diff
196
apps/elftosb/common/StELFFile.h
Normal file
196
apps/elftosb/common/StELFFile.h
Normal file
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* File: StELFFile.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
#if !defined(_StELFFile_h_)
|
||||
#define _StELFFile_h_
|
||||
|
||||
#include "stdafx.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include "ELF.h"
|
||||
|
||||
//! Variations of the ARM ELF format.
|
||||
typedef enum
|
||||
{
|
||||
eARMVariant = 1, //!< Standard ARM ELF specification.
|
||||
eGHSVariant, //!< Green Hills Software variant.
|
||||
eGCCVariant //!< GNU Compiler Collection variant.
|
||||
} ELFVariant_t;
|
||||
|
||||
//! Possible ARM ELF symbol types.
|
||||
typedef enum
|
||||
{
|
||||
eUnknownSymbol,
|
||||
eARMSymbol,
|
||||
eThumbSymbol,
|
||||
eDataSymbol
|
||||
} ARMSymbolType_t;
|
||||
|
||||
/*!
|
||||
* \brief Parser for Executable and Linking Format (ELF) files.
|
||||
*
|
||||
* The stream passed into the constructor needs to stay open for the life
|
||||
* of the object. This is because calls to getSectionDataAtIndex() and
|
||||
* getSegmentDataAtIndex() read the data directly from the input stream.
|
||||
*/
|
||||
class StELFFile
|
||||
{
|
||||
public:
|
||||
typedef std::vector<Elf32_Shdr>::const_iterator const_section_iterator;
|
||||
typedef std::vector<Elf32_Phdr>::const_iterator const_segment_iterator;
|
||||
|
||||
public:
|
||||
//! \brief Constructor.
|
||||
StELFFile(std::istream &inStream);
|
||||
|
||||
//! \brief Destructor.
|
||||
virtual ~StELFFile();
|
||||
|
||||
//! \name File format variant
|
||||
//@{
|
||||
//! \brief Return the ELF format variant to which this file is set.
|
||||
virtual ELFVariant_t ELFVariant() { return m_elfVariant; }
|
||||
//! \brief Set the ELF format variation to either #eARMVariant or #eGHSVariant.
|
||||
virtual void setELFVariant(ELFVariant_t variant) { m_elfVariant = variant; }
|
||||
//@}
|
||||
|
||||
//! \name File name
|
||||
//@{
|
||||
virtual void setName(const std::string &inName) { m_name = inName; }
|
||||
virtual std::string getName() const { return m_name; }
|
||||
//@}
|
||||
|
||||
//! \name ELF header
|
||||
//@{
|
||||
//! \brief Returns the ELF file header.
|
||||
inline const Elf32_Ehdr &getFileHeader() const { return m_header; }
|
||||
//@}
|
||||
|
||||
//! \name Sections
|
||||
//! Methods pertaining to the object file's sections.
|
||||
//@{
|
||||
//! \brief Returns the number of sections in the file.
|
||||
inline unsigned getSectionCount() const { return static_cast<unsigned>(m_sectionHeaders.size()); }
|
||||
//! \brief Returns a reference to section number \a inIndex.
|
||||
const Elf32_Shdr &getSectionAtIndex(unsigned inIndex) const;
|
||||
|
||||
inline const_section_iterator getSectionBegin() const { return m_sectionHeaders.begin(); }
|
||||
inline const_section_iterator getSectionEnd() const { return m_sectionHeaders.end(); }
|
||||
//! \brief Returns the index of the section with the name \a inName.
|
||||
unsigned getIndexOfSectionWithName(const std::string &inName);
|
||||
|
||||
//! \brief Returns the data for the section.
|
||||
uint8_t *getSectionDataAtIndex(unsigned inIndex);
|
||||
|
||||
//! \brief Returns the data for the section.
|
||||
uint8_t *getSectionData(const_section_iterator inSection);
|
||||
//@}
|
||||
|
||||
//! \name Segments
|
||||
//! Methods for accessing the file's program headers for segments.
|
||||
//@{
|
||||
//! \brief Returns the number of segments, or program headers, in the file.
|
||||
inline unsigned getSegmentCount() const { return static_cast<unsigned>(m_programHeaders.size()); }
|
||||
//! \brief Returns a reference to the given segment.
|
||||
const Elf32_Phdr &getSegmentAtIndex(unsigned inIndex) const;
|
||||
|
||||
inline const_segment_iterator getSegmentBegin() const { return m_programHeaders.begin(); }
|
||||
inline const_segment_iterator getSegmentEnd() const { return m_programHeaders.end(); }
|
||||
//! \brief Returns the data of the specified segment.
|
||||
uint8_t *getSegmentDataAtIndex(unsigned inIndex);
|
||||
|
||||
//! \brief Returns the data of the specified segment.
|
||||
uint8_t *getSegmentData(const_segment_iterator inSegment);
|
||||
//@}
|
||||
|
||||
//! \name String table
|
||||
//! Methods for accessing the string tables.
|
||||
//@{
|
||||
//! \brief Returns a string from the file's section name string table.
|
||||
std::string getSectionNameAtIndex(unsigned inIndex);
|
||||
|
||||
//! \brief Returns a string from any string table in the object file.
|
||||
std::string getStringAtIndex(unsigned inStringTableSectionIndex, unsigned inStringIndex);
|
||||
//@}
|
||||
|
||||
//! \name Symbol table
|
||||
//! Methods for accessing the object file's symbol table. Currently only
|
||||
//! a single symbol table with the section name ".symtab" is supported.
|
||||
//@{
|
||||
//! \brief Returns the number of symbols in the default ".symtab" symbol table.
|
||||
unsigned getSymbolCount();
|
||||
|
||||
//! \brief Returns the symbol with index \a inIndex.
|
||||
const Elf32_Sym &getSymbolAtIndex(unsigned inIndex);
|
||||
|
||||
//! \brief Returns the section index of the string table containing symbol names.
|
||||
unsigned getSymbolNameStringTableIndex() const;
|
||||
|
||||
//! \brief Returns the name of the symbol described by \a inSymbol.
|
||||
std::string getSymbolName(const Elf32_Sym &inSymbol);
|
||||
|
||||
unsigned getIndexOfSymbolAtAddress(uint32_t symbolAddress, bool strict = true);
|
||||
|
||||
ARMSymbolType_t getTypeOfSymbolAtIndex(unsigned symbolIndex);
|
||||
//@}
|
||||
|
||||
//! \name Debugging
|
||||
//@{
|
||||
void dumpSections();
|
||||
void dumpSymbolTable();
|
||||
//@}
|
||||
|
||||
protected:
|
||||
std::istream &m_stream; //!< The source stream for the ELF file.
|
||||
ELFVariant_t m_elfVariant; //!< Variant of the ARM ELF format specification.
|
||||
std::string m_name; //!< File name. (optional)
|
||||
Elf32_Ehdr m_header; //!< The ELF file header.
|
||||
std::vector<Elf32_Shdr> m_sectionHeaders; //!< All of the section headers.
|
||||
std::vector<Elf32_Phdr> m_programHeaders; //!< All of the program headers.
|
||||
unsigned m_symbolTableIndex; //!< Index of ".symtab" section, or #SHN_UNDEF if not present.
|
||||
|
||||
/*!
|
||||
* Little structure containing information about cached section data.
|
||||
*/
|
||||
struct SectionDataInfo
|
||||
{
|
||||
uint8_t *m_data; //!< Pointer to section data.
|
||||
unsigned m_size; //!< Section data size in bytes.
|
||||
bool m_swapped; //!< Has this section been byte swapped yet? Used for symbol table.
|
||||
};
|
||||
typedef std::map<unsigned, SectionDataInfo> SectionDataMap;
|
||||
SectionDataMap m_sectionDataCache; //!< Cached data of sections.
|
||||
|
||||
//! \brief Reads a section's data either from cache or from disk.
|
||||
SectionDataInfo &getCachedSectionData(unsigned inSectionIndex);
|
||||
|
||||
//! \brief Reads the file, section, and program headers into memory.
|
||||
void readFileHeaders();
|
||||
|
||||
uint8_t *readSectionData(const Elf32_Shdr &inHeader);
|
||||
uint8_t *readSegmentData(const Elf32_Phdr &inHeader);
|
||||
|
||||
//! \brief Byte swaps the symbol table data into host endianness.
|
||||
void byteSwapSymbolTable(const Elf32_Shdr &header, SectionDataInfo &info);
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Simple exception thrown to indicate an error in the input ELF file format.
|
||||
*/
|
||||
class StELFFileException : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
//! \brief Default constructor.
|
||||
StELFFileException(const std::string &inMessage)
|
||||
: std::runtime_error(inMessage)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
#endif // _StELFFile_h_
|
||||
464
apps/elftosb/common/StExecutableImage.cpp
Normal file
464
apps/elftosb/common/StExecutableImage.cpp
Normal file
@@ -0,0 +1,464 @@
|
||||
/*
|
||||
* File: StExecutableImage.cpp
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
|
||||
#include "StExecutableImage.h"
|
||||
#include <stdexcept>
|
||||
#include <algorithm>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
StExecutableImage::StExecutableImage(int inAlignment)
|
||||
: m_alignment(inAlignment)
|
||||
, m_hasEntry(false)
|
||||
, m_entry(0)
|
||||
{
|
||||
}
|
||||
|
||||
//! Makes a duplicate of each memory region.
|
||||
StExecutableImage::StExecutableImage(const StExecutableImage &inOther)
|
||||
: m_name(inOther.m_name)
|
||||
, m_alignment(inOther.m_alignment)
|
||||
, m_hasEntry(inOther.m_hasEntry)
|
||||
, m_entry(inOther.m_entry)
|
||||
, m_filters(inOther.m_filters)
|
||||
{
|
||||
const_iterator it = inOther.getRegionBegin();
|
||||
for (; it != inOther.getRegionEnd(); ++it)
|
||||
{
|
||||
const MemoryRegion ®ion = *it;
|
||||
|
||||
MemoryRegion regionCopy(region);
|
||||
if (region.m_type == FILL_REGION && region.m_data != NULL)
|
||||
{
|
||||
regionCopy.m_data = new uint8_t[region.m_length];
|
||||
memcpy(regionCopy.m_data, region.m_data, region.m_length);
|
||||
}
|
||||
|
||||
m_image.push_back(regionCopy);
|
||||
}
|
||||
}
|
||||
|
||||
//! Disposes of memory allocated for each region.
|
||||
StExecutableImage::~StExecutableImage()
|
||||
{
|
||||
MemoryRegionList::iterator it;
|
||||
for (it = m_image.begin(); it != m_image.end(); ++it)
|
||||
{
|
||||
if (it->m_data)
|
||||
{
|
||||
delete[] it->m_data;
|
||||
it->m_data = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//! A copy of \a inName is made, so the original may be disposed of by the caller
|
||||
//! after this method returns.
|
||||
void StExecutableImage::setName(const std::string &inName)
|
||||
{
|
||||
m_name = inName;
|
||||
}
|
||||
|
||||
std::string StExecutableImage::getName() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
// The region is added with read and write flags set.
|
||||
//! \exception std::runtime_error will be thrown if the new overlaps an
|
||||
//! existing region.
|
||||
void StExecutableImage::addFillRegion(uint32_t inAddress, unsigned inLength)
|
||||
{
|
||||
MemoryRegion region;
|
||||
region.m_type = FILL_REGION;
|
||||
region.m_address = inAddress;
|
||||
region.m_data = NULL;
|
||||
region.m_length = inLength;
|
||||
region.m_flags = REGION_RW_FLAG;
|
||||
|
||||
insertOrMergeRegion(region);
|
||||
}
|
||||
|
||||
//! A copy of \a inData is made before returning. The copy will be deleted when
|
||||
//! the executable image is destructed. Currently, the text region is created with
|
||||
//! read, write, and executable flags set.
|
||||
//! \exception std::runtime_error will be thrown if the new overlaps an
|
||||
//! existing region.
|
||||
//! \exception std::bad_alloc is thrown if memory for the copy of \a inData
|
||||
//! cannot be allocated.
|
||||
void StExecutableImage::addTextRegion(uint32_t inAddress, const uint8_t *inData, unsigned inLength)
|
||||
{
|
||||
MemoryRegion region;
|
||||
region.m_type = TEXT_REGION;
|
||||
region.m_address = inAddress;
|
||||
region.m_flags = REGION_RW_FLAG | REGION_EXEC_FLAG;
|
||||
|
||||
// copy the data
|
||||
region.m_data = new uint8_t[inLength];
|
||||
region.m_length = inLength;
|
||||
memcpy(region.m_data, inData, inLength);
|
||||
|
||||
insertOrMergeRegion(region);
|
||||
}
|
||||
|
||||
//! \exception std::out_of_range is thrown if \a inIndex is out of range.
|
||||
//!
|
||||
const StExecutableImage::MemoryRegion &StExecutableImage::getRegionAtIndex(unsigned inIndex) const
|
||||
{
|
||||
// check bounds
|
||||
if (inIndex >= m_image.size())
|
||||
throw std::out_of_range("inIndex");
|
||||
|
||||
// find region by index
|
||||
MemoryRegionList::const_iterator it = m_image.begin();
|
||||
unsigned i = 0;
|
||||
for (; it != m_image.end(); ++it, ++i)
|
||||
{
|
||||
if (i == inIndex)
|
||||
break;
|
||||
}
|
||||
return *it;
|
||||
}
|
||||
|
||||
//! The list of address filters is kept sorted as filters are added.
|
||||
//!
|
||||
void StExecutableImage::addAddressFilter(const AddressFilter &filter)
|
||||
{
|
||||
m_filters.push_back(filter);
|
||||
m_filters.sort();
|
||||
}
|
||||
|
||||
//!
|
||||
void StExecutableImage::clearAddressFilters()
|
||||
{
|
||||
m_filters.clear();
|
||||
}
|
||||
|
||||
//! \exception StExecutableImage::address_filter_exception Raised when a filter
|
||||
//! with the type #ADDR_FILTER_ERROR or #ADDR_FILTER_WARNING is matched.
|
||||
//!
|
||||
//! \todo Build a list of all matching filters and then execute them at once.
|
||||
//! For the warning and error filters, a single exception should be raised
|
||||
//! that identifies all the overlapping errors. Currently the user will only
|
||||
//! see the first (lowest address) overlap.
|
||||
void StExecutableImage::applyAddressFilters()
|
||||
{
|
||||
restart_loops:
|
||||
// Iterate over filters.
|
||||
AddressFilterList::const_iterator fit = m_filters.begin();
|
||||
for (; fit != m_filters.end(); ++fit)
|
||||
{
|
||||
const AddressFilter &filter = *fit;
|
||||
|
||||
// Iterator over regions.
|
||||
MemoryRegionList::iterator rit = m_image.begin();
|
||||
for (; rit != m_image.end(); ++rit)
|
||||
{
|
||||
MemoryRegion ®ion = *rit;
|
||||
|
||||
if (filter.matchesMemoryRegion(region))
|
||||
{
|
||||
switch (filter.m_action)
|
||||
{
|
||||
case ADDR_FILTER_NONE:
|
||||
// Do nothing.
|
||||
break;
|
||||
|
||||
case ADDR_FILTER_ERROR:
|
||||
// throw error exception
|
||||
throw address_filter_exception(true, m_name, filter);
|
||||
break;
|
||||
|
||||
case ADDR_FILTER_WARNING:
|
||||
// throw warning exception
|
||||
throw address_filter_exception(false, m_name, filter);
|
||||
break;
|
||||
|
||||
case ADDR_FILTER_CROP:
|
||||
// Delete the offending portion of the region and restart
|
||||
// the iteration loops.
|
||||
cropRegionToFilter(region, filter);
|
||||
goto restart_loops;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//! There are several possible cases here:
|
||||
//! - No overlap at all. Nothing is done.
|
||||
//!
|
||||
//! - All of the memory region is matched by the \a filter. The region is
|
||||
//! removed from #StExecutableImage::m_image and its data memory freed.
|
||||
//!
|
||||
//! - The remaining portion of the region is one contiguous chunk. In this
|
||||
//! case, \a region is simply modified.
|
||||
//!
|
||||
//! - The region is split in the middle by the filter. The original \a region
|
||||
//! is modified to match the first remaining chunk. And a new #StExecutableImage::MemoryRegion
|
||||
//! instance is created to hold the other leftover piece.
|
||||
void StExecutableImage::cropRegionToFilter(MemoryRegion ®ion, const AddressFilter &filter)
|
||||
{
|
||||
uint32_t firstByte = region.m_address; // first byte occupied by this region
|
||||
uint32_t lastByte = region.endAddress(); // last used byte in this region
|
||||
|
||||
// compute new address range
|
||||
uint32_t cropFrom = filter.m_fromAddress;
|
||||
if (cropFrom < firstByte)
|
||||
{
|
||||
cropFrom = firstByte;
|
||||
}
|
||||
|
||||
uint32_t cropTo = filter.m_toAddress;
|
||||
if (cropTo > lastByte)
|
||||
{
|
||||
cropTo = lastByte;
|
||||
}
|
||||
|
||||
// is there actually a match?
|
||||
if (cropFrom > filter.m_toAddress || cropTo < filter.m_fromAddress)
|
||||
{
|
||||
// nothing to do, so bail
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Deleting region 0x%08x-0x%08x\n", cropFrom, cropTo);
|
||||
|
||||
// handle if the entire region is to be deleted
|
||||
if (cropFrom == firstByte && cropTo == lastByte)
|
||||
{
|
||||
delete[] region.m_data;
|
||||
region.m_data = NULL;
|
||||
m_image.remove(region);
|
||||
}
|
||||
|
||||
// there is at least a little of the original region remaining
|
||||
uint32_t newLength = cropTo - cropFrom + 1;
|
||||
uint32_t leftoverLength = lastByte - cropTo;
|
||||
uint8_t *oldData = region.m_data;
|
||||
|
||||
// update the region
|
||||
region.m_address = cropFrom;
|
||||
region.m_length = newLength;
|
||||
|
||||
// crop data buffer for text regions
|
||||
if (region.m_type == TEXT_REGION && oldData)
|
||||
{
|
||||
region.m_data = new uint8_t[newLength];
|
||||
memcpy(region.m_data, &oldData[cropFrom - firstByte], newLength);
|
||||
|
||||
// dispose of old data
|
||||
delete[] oldData;
|
||||
}
|
||||
|
||||
// create a new region for any part of the original region that was past
|
||||
// the crop to address. this will happen if the filter range falls in the
|
||||
// middle of the region.
|
||||
if (leftoverLength)
|
||||
{
|
||||
MemoryRegion newRegion;
|
||||
newRegion.m_type = region.m_type;
|
||||
newRegion.m_flags = region.m_flags;
|
||||
newRegion.m_address = cropTo + 1;
|
||||
newRegion.m_length = leftoverLength;
|
||||
|
||||
if (region.m_type == TEXT_REGION && oldData)
|
||||
{
|
||||
newRegion.m_data = new uint8_t[leftoverLength];
|
||||
memcpy(newRegion.m_data, &oldData[cropTo - firstByte + 1], leftoverLength);
|
||||
}
|
||||
|
||||
insertOrMergeRegion(newRegion);
|
||||
}
|
||||
}
|
||||
|
||||
//! \exception std::runtime_error will be thrown if \a inRegion overlaps an
|
||||
//! existing region.
|
||||
//!
|
||||
//! \todo Need to investigate if we can use the STL sort algorithm at all. Even
|
||||
//! though we're doing merges too, we could sort first then examine the list
|
||||
//! for merges.
|
||||
void StExecutableImage::insertOrMergeRegion(MemoryRegion &inRegion)
|
||||
{
|
||||
uint32_t newStart = inRegion.m_address;
|
||||
uint32_t newEnd = newStart + inRegion.m_length;
|
||||
|
||||
MemoryRegionList::iterator it = m_image.begin();
|
||||
// MemoryRegionList::iterator sortedPosition = m_image.begin();
|
||||
for (; it != m_image.end(); ++it)
|
||||
{
|
||||
MemoryRegion ®ion = *it;
|
||||
uint32_t thisStart = region.m_address;
|
||||
uint32_t thisEnd = thisStart + region.m_length;
|
||||
|
||||
// keep track of where to insert it to retain sort order
|
||||
if (thisStart >= newEnd)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// region types and flags must match in order to merge
|
||||
if (region.m_type == inRegion.m_type && region.m_flags == inRegion.m_flags)
|
||||
{
|
||||
if (newStart == thisEnd || newEnd == thisStart)
|
||||
{
|
||||
mergeRegions(region, inRegion);
|
||||
return;
|
||||
}
|
||||
else if ((newStart >= thisStart && newStart < thisEnd) || (newEnd >= thisStart && newEnd < thisEnd))
|
||||
{
|
||||
throw std::runtime_error("new region overlaps existing region");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// not merged, so just insert it in the sorted position
|
||||
m_image.insert(it, inRegion);
|
||||
}
|
||||
|
||||
//! Extends \a inNewRegion to include the data in \a inOldRegion. It is
|
||||
//! assumed that the two regions are compatible. The new region may come either
|
||||
//! before or after the old region in memory. Note that while the two regions
|
||||
//! don't necessarily have to be touching, it's probably a good idea. That's
|
||||
//! because any data between the regions will be set to 0.
|
||||
//!
|
||||
//! For TEXT_REGION types, the two original regions will have their data deleted
|
||||
//! during the merge. Thus, this method is not safe if any outside callers may
|
||||
//! be accessing the region's data.
|
||||
void StExecutableImage::mergeRegions(MemoryRegion &inOldRegion, MemoryRegion &inNewRegion)
|
||||
{
|
||||
bool isOldBefore = inOldRegion.m_address < inNewRegion.m_address;
|
||||
uint32_t oldEnd = inOldRegion.m_address + inOldRegion.m_length;
|
||||
uint32_t newEnd = inNewRegion.m_address + inNewRegion.m_length;
|
||||
|
||||
switch (inOldRegion.m_type)
|
||||
{
|
||||
case TEXT_REGION:
|
||||
{
|
||||
// calculate new length
|
||||
unsigned newLength;
|
||||
if (isOldBefore)
|
||||
{
|
||||
newLength = newEnd - inOldRegion.m_address;
|
||||
}
|
||||
else
|
||||
{
|
||||
newLength = oldEnd - inNewRegion.m_address;
|
||||
}
|
||||
|
||||
// alloc memory
|
||||
uint8_t *newData = new uint8_t[newLength];
|
||||
memset(newData, 0, newLength);
|
||||
|
||||
// copy data from the two regions into new block
|
||||
if (isOldBefore)
|
||||
{
|
||||
memcpy(newData, inOldRegion.m_data, inOldRegion.m_length);
|
||||
memcpy(&newData[newLength - inNewRegion.m_length], inNewRegion.m_data, inNewRegion.m_length);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(newData, inNewRegion.m_data, inNewRegion.m_length);
|
||||
memcpy(&newData[newLength - inOldRegion.m_length], inOldRegion.m_data, inOldRegion.m_length);
|
||||
|
||||
inOldRegion.m_address = inNewRegion.m_address;
|
||||
}
|
||||
|
||||
// replace old region's data
|
||||
delete[] inOldRegion.m_data;
|
||||
inOldRegion.m_data = newData;
|
||||
inOldRegion.m_length = newLength;
|
||||
|
||||
// delete new region's data
|
||||
delete[] inNewRegion.m_data;
|
||||
inNewRegion.m_data = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
case FILL_REGION:
|
||||
{
|
||||
if (isOldBefore)
|
||||
{
|
||||
inOldRegion.m_length = newEnd - inOldRegion.m_address;
|
||||
}
|
||||
else
|
||||
{
|
||||
inOldRegion.m_length = oldEnd - inNewRegion.m_address;
|
||||
inOldRegion.m_address = inNewRegion.m_address;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//! Used when we remove a region from the region list by value. Because this
|
||||
//! operator compares the #m_data member, it will only return true for either an
|
||||
//! exact copy or a reference to the original.
|
||||
bool StExecutableImage::MemoryRegion::operator==(const MemoryRegion &other) const
|
||||
{
|
||||
return (m_type == other.m_type) && (m_address == other.m_address) && (m_length == other.m_length) &&
|
||||
(m_flags == other.m_flags) && (m_data == other.m_data);
|
||||
}
|
||||
|
||||
//! Returns true if the address filter overlaps \a region.
|
||||
bool StExecutableImage::AddressFilter::matchesMemoryRegion(const MemoryRegion ®ion) const
|
||||
{
|
||||
uint32_t firstByte = region.m_address; // first byte occupied by this region
|
||||
uint32_t lastByte = region.endAddress(); // last used byte in this region
|
||||
return (firstByte >= m_fromAddress && firstByte <= m_toAddress) ||
|
||||
(lastByte >= m_fromAddress && lastByte <= m_toAddress);
|
||||
}
|
||||
|
||||
//! The comparison does \em not take the action into account. It only looks at the
|
||||
//! priority and address ranges of each filter. Priority is considered only if the two
|
||||
//! filters overlap. Lower priority filters will come after higher priority ones.
|
||||
//!
|
||||
//! \retval -1 This filter is less than filter \a b.
|
||||
//! \retval 0 This filter is equal to filter \a b.
|
||||
//! \retval 1 This filter is greater than filter \a b.
|
||||
int StExecutableImage::AddressFilter::compare(const AddressFilter &other) const
|
||||
{
|
||||
if (m_priority != other.m_priority &&
|
||||
((m_fromAddress >= other.m_fromAddress && m_fromAddress <= other.m_toAddress) ||
|
||||
(m_toAddress >= other.m_fromAddress && m_toAddress <= other.m_toAddress)))
|
||||
{
|
||||
// we know the priorities are not equal
|
||||
if (m_priority > other.m_priority)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_fromAddress == other.m_fromAddress)
|
||||
{
|
||||
if (m_toAddress == other.m_toAddress)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else if (m_toAddress < other.m_toAddress)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if (m_fromAddress < other.m_fromAddress)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
257
apps/elftosb/common/StExecutableImage.h
Normal file
257
apps/elftosb/common/StExecutableImage.h
Normal file
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
* File: StExecutableImage.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
#if !defined(_StExecutableImage_h_)
|
||||
#define _StExecutableImage_h_
|
||||
|
||||
#include "stdafx.h"
|
||||
#include <list>
|
||||
|
||||
/*!
|
||||
* \brief Used to build a representation of memory regions.
|
||||
*
|
||||
* An intermediate representation of the memory regions and segments loaded
|
||||
* from an executable file. Also used to find contiguous segments that are
|
||||
* specified separately in the source file.
|
||||
*
|
||||
* When regions are added, an attempt is made to coalesce contiguous regions.
|
||||
* In order for this to succeed, the touching regions must be of the same
|
||||
* type and have the same permissions. Regions are also kept sorted by their
|
||||
* address range as they are added.
|
||||
*
|
||||
* \todo Implement alignment support.
|
||||
*/
|
||||
class StExecutableImage
|
||||
{
|
||||
public:
|
||||
//! Possible types of memory regions.
|
||||
typedef enum
|
||||
{
|
||||
TEXT_REGION, //!< A region containing data or instructions.
|
||||
FILL_REGION //!< Region to be initialized with zero bytes.
|
||||
} MemoryRegionType;
|
||||
|
||||
//! Memory region flag constants.
|
||||
enum
|
||||
{
|
||||
REGION_READ_FLAG = 1, //!< Region is readable.
|
||||
REGION_WRITE_FLAG = 2, //!< Region is writable.
|
||||
REGION_EXEC_FLAG = 4, //!< Region may contain executable code.
|
||||
|
||||
REGION_RW_FLAG = REGION_READ_FLAG | REGION_WRITE_FLAG, //!< Region is read-write.
|
||||
|
||||
//! Mask to access only permissions flags for a region.
|
||||
REGION_PERM_FLAG_MASK = 0x7
|
||||
};
|
||||
|
||||
/*!
|
||||
* Representation of a contiguous region of memory.
|
||||
*
|
||||
* \todo Add comparison operators so we can use the STL sort algorithm.
|
||||
*/
|
||||
struct MemoryRegion
|
||||
{
|
||||
MemoryRegionType m_type; //!< Memory region type.
|
||||
uint32_t m_address; //!< The 32-bit start address of this region.
|
||||
uint32_t m_length; //!< Number of bytes in this region.
|
||||
uint8_t *m_data; //!< Pointer to data. Will be NULL for FILL_REGION type.
|
||||
unsigned m_flags; //!< Flags for the region.
|
||||
|
||||
//! \brief Calculates the address of the last byte occupied by this region.
|
||||
inline uint32_t endAddress() const { return m_address + m_length - 1; }
|
||||
//! \brief Equality operator.
|
||||
bool operator==(const MemoryRegion &other) const;
|
||||
};
|
||||
|
||||
//! A list of #StExecutableImage::MemoryRegion objects.
|
||||
typedef std::list<MemoryRegion> MemoryRegionList;
|
||||
|
||||
//! The iterator type used to access #StExecutableImage::MemoryRegion objects. This type
|
||||
//! is used by the methods #getRegionBegin() and #getRegionEnd().
|
||||
typedef MemoryRegionList::const_iterator const_iterator;
|
||||
|
||||
//! The possible actions for regions matching an address filter range.
|
||||
typedef enum
|
||||
{
|
||||
ADDR_FILTER_NONE, //!< Do nothing.
|
||||
ADDR_FILTER_ERROR, //!< Raise an error exception.
|
||||
ADDR_FILTER_WARNING, //!< Raise a warning exception.
|
||||
ADDR_FILTER_CROP //!< Don't include the matching address range in the executable image.
|
||||
} AddressFilterAction;
|
||||
|
||||
/*!
|
||||
* An address filter consists of a single address range and an action. If a
|
||||
* memory region overlaps the filter's range then the action will be performed.
|
||||
* The possible filter actions are defined by the #AddressFilterAction enumeration.
|
||||
*/
|
||||
struct AddressFilter
|
||||
{
|
||||
AddressFilterAction m_action; //!< Action to be performed when the filter is matched.
|
||||
uint32_t m_fromAddress; //!< Start address of the filter. Should be lower than or equal to #m_toAddress.
|
||||
uint32_t m_toAddress; //!< End address of the filter. Should be higher than or equal to #m_fromAddress.
|
||||
unsigned m_priority; //!< Priority for this filter. Zero is the lowest priority.
|
||||
|
||||
//! \brief Constructor.
|
||||
AddressFilter(AddressFilterAction action, uint32_t from, uint32_t to, unsigned priority = 0)
|
||||
: m_action(action)
|
||||
, m_fromAddress(from)
|
||||
, m_toAddress(to)
|
||||
, m_priority(priority)
|
||||
{
|
||||
}
|
||||
|
||||
//! \brief Test routine.
|
||||
bool matchesMemoryRegion(const MemoryRegion ®ion) const;
|
||||
|
||||
//! \brief Compares two address filter objects.
|
||||
int compare(const AddressFilter &other) const;
|
||||
|
||||
//! \name Comparison operators
|
||||
//@{
|
||||
inline bool operator<(const AddressFilter &other) const { return compare(other) == -1; }
|
||||
inline bool operator>(const AddressFilter &other) const { return compare(other) == 1; }
|
||||
inline bool operator==(const AddressFilter &other) const { return compare(other) == 0; }
|
||||
inline bool operator<=(const AddressFilter &other) const { return compare(other) != 1; }
|
||||
inline bool operator>=(const AddressFilter &other) const { return compare(other) != -1; }
|
||||
//@}
|
||||
};
|
||||
|
||||
//! List of #StExecutableImage::AddressFilter objects.
|
||||
typedef std::list<AddressFilter> AddressFilterList;
|
||||
|
||||
//! The exception class raised for the #ADDR_FILTER_ERROR and #ADDR_FILTER_WARNING
|
||||
//! filter actions.
|
||||
class address_filter_exception
|
||||
{
|
||||
public:
|
||||
//! \brief Constructor.
|
||||
//!
|
||||
//! A local copy of \a matchingFilter is made, in case the image and/or filter
|
||||
//! are on the stack and would be disposed of when the exception is raised.
|
||||
address_filter_exception(bool isError, std::string &imageName, const AddressFilter &matchingFilter)
|
||||
: m_isError(isError)
|
||||
, m_imageName(imageName)
|
||||
, m_filter(matchingFilter)
|
||||
{
|
||||
}
|
||||
|
||||
//! \brief Returns true if the exception is an error. Otherwise the exception
|
||||
//! is for a warning.
|
||||
inline bool isError() const { return m_isError; }
|
||||
//! \brief
|
||||
inline std::string getImageName() const { return m_imageName; }
|
||||
//! \brief
|
||||
inline const AddressFilter &getMatchingFilter() const { return m_filter; }
|
||||
protected:
|
||||
bool m_isError;
|
||||
std::string m_imageName;
|
||||
AddressFilter m_filter;
|
||||
};
|
||||
|
||||
public:
|
||||
//! \brief Constructor.
|
||||
StExecutableImage(int inAlignment = 256);
|
||||
|
||||
//! \brief Copy constructor.
|
||||
StExecutableImage(const StExecutableImage &inOther);
|
||||
|
||||
//! \brief Destructor.
|
||||
virtual ~StExecutableImage();
|
||||
|
||||
//! \name Image name
|
||||
//! Methods for getting and setting the image name.
|
||||
//@{
|
||||
//! \brief Sets the image's name to \a inName.
|
||||
virtual void setName(const std::string &inName);
|
||||
|
||||
//! \brief Returns a copy of the image's name.
|
||||
virtual std::string getName() const;
|
||||
//@}
|
||||
|
||||
//! \name Regions
|
||||
//! Methods to add and access memory regions.
|
||||
//@{
|
||||
//! \brief Add a region to be filled with zeroes.
|
||||
virtual void addFillRegion(uint32_t inAddress, unsigned inLength);
|
||||
|
||||
//! \brief Add a region containing data to be loaded.
|
||||
virtual void addTextRegion(uint32_t inAddress, const uint8_t *inData, unsigned inLength);
|
||||
|
||||
//! \brief Returns the total number of regions.
|
||||
//!
|
||||
//! Note that this count may not be the same as the number of calls to
|
||||
//! addFillRegion() and addTextRegion() due to region coalescing.
|
||||
inline unsigned getRegionCount() const { return static_cast<unsigned>(m_image.size()); }
|
||||
//! \brief Returns a reference to the region specified by \a inIndex.
|
||||
const MemoryRegion &getRegionAtIndex(unsigned inIndex) const;
|
||||
|
||||
//! \brief Return an iterator to the first region.
|
||||
inline const_iterator getRegionBegin() const { return m_image.begin(); }
|
||||
//! \brief Return an iterator to the next-after-last region.
|
||||
inline const_iterator getRegionEnd() const { return m_image.end(); }
|
||||
//@}
|
||||
|
||||
//! \name Entry point
|
||||
//@{
|
||||
//! \brief Sets the entry point address.
|
||||
inline void setEntryPoint(uint32_t inEntryAddress)
|
||||
{
|
||||
m_entry = inEntryAddress;
|
||||
m_hasEntry = true;
|
||||
}
|
||||
|
||||
//! \brief Returns true if an entry point has been set.
|
||||
inline bool hasEntryPoint() const { return m_hasEntry; }
|
||||
//! \brief Returns the entry point address.
|
||||
inline uint32_t getEntryPoint() const { return hasEntryPoint() ? m_entry : 0; }
|
||||
//@}
|
||||
|
||||
//! \name Address filter
|
||||
//@{
|
||||
//! \brief Add a new address filter.
|
||||
virtual void addAddressFilter(const AddressFilter &filter);
|
||||
|
||||
//! \brief Add multiple address filters at once.
|
||||
//!
|
||||
//! The template argument \a _T must be an iterator or const iterator that
|
||||
//! dereferences to an StExecutableImage::AddressFilter reference. All filters
|
||||
//! from \a from to \a to will be added to the address filter list.
|
||||
template <typename _T>
|
||||
void addAddressFilters(_T from, _T to)
|
||||
{
|
||||
_T it = from;
|
||||
for (; it != to; ++it)
|
||||
{
|
||||
addAddressFilter(*it);
|
||||
}
|
||||
}
|
||||
|
||||
//! \brief Remove all active filters.
|
||||
virtual void clearAddressFilters();
|
||||
|
||||
//! \brief Process all active filters and perform associated actions.
|
||||
virtual void applyAddressFilters();
|
||||
//@}
|
||||
|
||||
protected:
|
||||
std::string m_name; //!< The name of the image (can be a file name, for instance).
|
||||
int m_alignment; //!< The required address alignment for each memory region.
|
||||
bool m_hasEntry; //!< True if an entry point has been set.
|
||||
uint32_t m_entry; //!< Entry point address.
|
||||
MemoryRegionList m_image; //!< The memory regions.
|
||||
AddressFilterList m_filters; //!< List of active address filters.
|
||||
|
||||
//! \brief Deletes the portion \a region that overlaps \a filter.
|
||||
void cropRegionToFilter(MemoryRegion ®ion, const AddressFilter &filter);
|
||||
|
||||
//! \brief Inserts the region in sorted order or merges with one already in the image.
|
||||
void insertOrMergeRegion(MemoryRegion &inRegion);
|
||||
|
||||
//! \brief Merges two memory regions into one.
|
||||
void mergeRegions(MemoryRegion &inOldRegion, MemoryRegion &inNewRegion);
|
||||
};
|
||||
|
||||
#endif // _StExecutableImage_h_
|
||||
236
apps/elftosb/common/StSRecordFile.cpp
Normal file
236
apps/elftosb/common/StSRecordFile.cpp
Normal file
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
* File: StSRecordFile.cpp
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "StSRecordFile.h"
|
||||
#include "string.h"
|
||||
|
||||
StSRecordFile::StSRecordFile(std::istream &inStream)
|
||||
: m_stream(inStream)
|
||||
{
|
||||
}
|
||||
|
||||
//! Frees any data allocated as part of an S-record.
|
||||
StSRecordFile::~StSRecordFile()
|
||||
{
|
||||
const_iterator it;
|
||||
for (it = m_records.begin(); it != m_records.end(); it++)
|
||||
{
|
||||
SRecord &theRecord = (SRecord &)*it;
|
||||
if (theRecord.m_data)
|
||||
{
|
||||
delete[] theRecord.m_data;
|
||||
theRecord.m_data = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//! Just looks for "S[0-9]" as the first two characters of the file.
|
||||
bool StSRecordFile::isSRecordFile()
|
||||
{
|
||||
int savePosition = static_cast<int>(m_stream.tellg());
|
||||
m_stream.seekg(0, std::ios_base::beg);
|
||||
|
||||
char buffer[2];
|
||||
m_stream.read(buffer, 2);
|
||||
bool isSRecord = (buffer[0] == 'S' && isdigit(buffer[1]));
|
||||
|
||||
m_stream.seekg(savePosition, std::ios_base::beg);
|
||||
|
||||
return isSRecord;
|
||||
}
|
||||
|
||||
//! Extract records one line at a time and hand them to the parseLine()
|
||||
//! method. Either CR, LF, or CRLF line endings are supported. The input
|
||||
//! stream is read until EOF.
|
||||
//! The parse() method must be called after the object has been constructed
|
||||
//! before any of the records will become accessible.
|
||||
//! \exception StSRecordParseException will be thrown if any error occurs while
|
||||
//! parsing the input.
|
||||
void StSRecordFile::parse()
|
||||
{
|
||||
// back to start of stream
|
||||
m_stream.seekg(0, std::ios_base::beg);
|
||||
|
||||
std::string thisLine;
|
||||
|
||||
do
|
||||
{
|
||||
char thisChar;
|
||||
m_stream.get(thisChar);
|
||||
|
||||
if (thisChar == '\r' || thisChar == '\n')
|
||||
{
|
||||
// skip the LF in a CRLF
|
||||
if (thisChar == '\r' && m_stream.peek() == '\n')
|
||||
m_stream.ignore();
|
||||
|
||||
// parse line if it's not empty
|
||||
if (!thisLine.empty())
|
||||
{
|
||||
parseLine(thisLine);
|
||||
|
||||
// reset line
|
||||
thisLine.clear();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
thisLine += thisChar;
|
||||
}
|
||||
} while (!m_stream.eof());
|
||||
}
|
||||
|
||||
bool StSRecordFile::isHexDigit(char c)
|
||||
{
|
||||
return (isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'));
|
||||
}
|
||||
|
||||
int StSRecordFile::hexDigitToInt(char digit)
|
||||
{
|
||||
if (isdigit(digit))
|
||||
return digit - '0';
|
||||
else if (digit >= 'a' && digit <= 'f')
|
||||
return 10 + digit - 'a';
|
||||
else if (digit >= 'A' && digit <= 'F')
|
||||
return 10 + digit - 'A';
|
||||
|
||||
// unknow char
|
||||
return 0;
|
||||
}
|
||||
|
||||
//! \exception StSRecordParseException is thrown if either of the nibble characters
|
||||
//! is not a valid hex digit.
|
||||
int StSRecordFile::readHexByte(std::string &inString, int inIndex)
|
||||
{
|
||||
char nibbleCharHi = inString[inIndex];
|
||||
char nibbleCharLo = inString[inIndex + 1];
|
||||
|
||||
// must be hex digits
|
||||
if (!(isHexDigit(nibbleCharHi) && isHexDigit(nibbleCharLo)))
|
||||
{
|
||||
throw StSRecordParseException("invalid hex digit");
|
||||
}
|
||||
|
||||
return (hexDigitToInt(nibbleCharHi) << 4) | hexDigitToInt(nibbleCharLo);
|
||||
}
|
||||
|
||||
//! \brief Parses individual S-records.
|
||||
//!
|
||||
//! Takes a single S-record line as input and appends a new SRecord struct
|
||||
//! to the m_records vector.
|
||||
//! \exception StSRecordParseException will be thrown if any error occurs while
|
||||
//! parsing \a inLine.
|
||||
void StSRecordFile::parseLine(std::string &inLine)
|
||||
{
|
||||
int checksum = 0;
|
||||
SRecord newRecord;
|
||||
memset(&newRecord, 0, sizeof(newRecord));
|
||||
|
||||
// must start with "S" and be at least a certain length
|
||||
if (inLine[0] != SRECORD_START_CHAR && inLine.length() >= SRECORD_MIN_LENGTH)
|
||||
{
|
||||
throw StSRecordParseException("invalid record length");
|
||||
}
|
||||
|
||||
// parse type field
|
||||
char typeChar = inLine[1];
|
||||
if (!isdigit(typeChar))
|
||||
{
|
||||
throw StSRecordParseException("invalid S-record type");
|
||||
}
|
||||
newRecord.m_type = typeChar - '0';
|
||||
|
||||
// parse count field
|
||||
newRecord.m_count = readHexByte(inLine, 2);
|
||||
checksum += newRecord.m_count;
|
||||
|
||||
// verify the record length now that we know the count
|
||||
if (inLine.length() != 4 + newRecord.m_count * 2)
|
||||
{
|
||||
throw StSRecordParseException("invalid record length");
|
||||
}
|
||||
|
||||
// get address length
|
||||
int addressLength = 0; // len in bytes
|
||||
bool hasData = false;
|
||||
switch (newRecord.m_type)
|
||||
{
|
||||
case 0: // contains header information
|
||||
addressLength = 2;
|
||||
hasData = true;
|
||||
break;
|
||||
case 1: // data record with 2-byte address
|
||||
addressLength = 2;
|
||||
hasData = true;
|
||||
break;
|
||||
case 2: // data record with 3-byte address
|
||||
addressLength = 3;
|
||||
hasData = true;
|
||||
break;
|
||||
case 3: // data record with 4-byte address
|
||||
addressLength = 4;
|
||||
hasData = true;
|
||||
break;
|
||||
case 5: // the 2-byte address field contains a count of all prior S1, S2, and S3 records
|
||||
addressLength = 2;
|
||||
break;
|
||||
case 7: // entry point record with 4-byte address
|
||||
addressLength = 4;
|
||||
break;
|
||||
case 8: // entry point record with 3-byte address
|
||||
addressLength = 3;
|
||||
break;
|
||||
case 9: // entry point record with 2-byte address
|
||||
addressLength = 2;
|
||||
break;
|
||||
default:
|
||||
// unrecognized type
|
||||
// throw StSRecordParseException("unknown S-record type");
|
||||
break;
|
||||
}
|
||||
|
||||
// read address
|
||||
int address = 0;
|
||||
int i;
|
||||
for (i = 0; i < addressLength; ++i)
|
||||
{
|
||||
int addressByte = readHexByte(inLine, SRECORD_ADDRESS_START_CHAR_INDEX + i * 2);
|
||||
address = (address << 8) | addressByte;
|
||||
checksum += addressByte;
|
||||
}
|
||||
newRecord.m_address = address;
|
||||
|
||||
// read data
|
||||
if (hasData)
|
||||
{
|
||||
int dataStartCharIndex = 4 + addressLength * 2;
|
||||
int dataLength = newRecord.m_count - addressLength - 1; // total rem - addr - cksum (in bytes)
|
||||
uint8_t *data = new uint8_t[dataLength];
|
||||
|
||||
for (i = 0; i < dataLength; ++i)
|
||||
{
|
||||
int dataByte = readHexByte(inLine, dataStartCharIndex + i * 2);
|
||||
data[i] = dataByte;
|
||||
checksum += dataByte;
|
||||
}
|
||||
|
||||
newRecord.m_data = data;
|
||||
newRecord.m_dataCount = dataLength;
|
||||
}
|
||||
|
||||
// read and compare checksum byte
|
||||
checksum = (~checksum) & 0xff; // low byte of one's complement of sum of other bytes
|
||||
newRecord.m_checksum = readHexByte(inLine, (int)inLine.length() - 2);
|
||||
if (checksum != newRecord.m_checksum)
|
||||
{
|
||||
throw StSRecordParseException("invalid checksum");
|
||||
}
|
||||
|
||||
// now save the new S-record
|
||||
m_records.push_back(newRecord);
|
||||
}
|
||||
122
apps/elftosb/common/StSRecordFile.h
Normal file
122
apps/elftosb/common/StSRecordFile.h
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* File: StSRecordFile.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
#if !defined(_StSRecordFile_h_)
|
||||
#define _StSRecordFile_h_
|
||||
|
||||
//#include <stdint.h>
|
||||
#include "stdafx.h"
|
||||
#include <istream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
|
||||
enum
|
||||
{
|
||||
//! The required first character of an S-record.
|
||||
SRECORD_START_CHAR = 'S',
|
||||
|
||||
//! The minimum length of a S-record. This is the type (2) + count (2) + addr (4) + cksum (2).
|
||||
SRECORD_MIN_LENGTH = 10,
|
||||
|
||||
//! Index of the first character of the address field.
|
||||
SRECORD_ADDRESS_START_CHAR_INDEX = 4
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief S-record parser.
|
||||
*
|
||||
* This class takes an input stream and parses it as an S-record file. While
|
||||
* the individual records that comprise the file are available for access, the
|
||||
* class also provides a higher-level view of the contents. It processes the
|
||||
* individual records and builds an image of what the memory touched by the
|
||||
* file looks like. Then you can access the contiguous sections of memory.
|
||||
*/
|
||||
class StSRecordFile
|
||||
{
|
||||
public:
|
||||
/*!
|
||||
* Structure representing each individual line of the S-record input data.
|
||||
*/
|
||||
struct SRecord
|
||||
{
|
||||
unsigned m_type; //!< Record number type, such as 9 for "S9", 3 for "S3" and so on.
|
||||
unsigned m_count; //!< Number of character pairs (bytes) from address through checksum.
|
||||
uint32_t m_address; //!< The address specified as part of the S-record.
|
||||
unsigned m_dataCount; //!< Number of bytes of data.
|
||||
uint8_t *m_data; //!< Pointer to data, or NULL if no data for this record type.
|
||||
uint8_t m_checksum; //!< The checksum byte present in the S-record.
|
||||
};
|
||||
|
||||
//! Iterator type.
|
||||
typedef std::vector<SRecord>::const_iterator const_iterator;
|
||||
|
||||
public:
|
||||
//! \brief Constructor.
|
||||
StSRecordFile(std::istream &inStream);
|
||||
|
||||
//! \brief Destructor.
|
||||
virtual ~StSRecordFile();
|
||||
|
||||
//! \name File name
|
||||
//@{
|
||||
virtual void setName(const std::string &inName) { m_name = inName; }
|
||||
virtual std::string getName() const { return m_name; }
|
||||
//@}
|
||||
|
||||
//! \name Parsing
|
||||
//@{
|
||||
//! \brief Determine if the file is an S-record file.
|
||||
virtual bool isSRecordFile();
|
||||
|
||||
//! \brief Parses the entire S-record input stream.
|
||||
virtual void parse();
|
||||
//@}
|
||||
|
||||
//! \name Record access
|
||||
//@{
|
||||
//! \return the number of S-records that have been parsed from the input stream.
|
||||
inline unsigned getRecordCount() const { return static_cast<unsigned>(m_records.size()); }
|
||||
//! \return iterator for
|
||||
inline const_iterator getBegin() const { return m_records.begin(); }
|
||||
inline const_iterator getEnd() const { return m_records.end(); }
|
||||
//@}
|
||||
|
||||
//! \name Operators
|
||||
//@{
|
||||
inline const SRecord &operator[](unsigned inIndex) { return m_records[inIndex]; }
|
||||
//@}
|
||||
|
||||
protected:
|
||||
std::istream &m_stream; //!< The input stream for the S-record data.
|
||||
std::vector<SRecord> m_records; //!< Vector of S-records in the input data.
|
||||
|
||||
std::string m_name; //!< File name. (optional)
|
||||
|
||||
//! \name Parsing utilities
|
||||
//@{
|
||||
virtual void parseLine(std::string &inLine);
|
||||
|
||||
bool isHexDigit(char c);
|
||||
int hexDigitToInt(char digit);
|
||||
int readHexByte(std::string &inString, int inIndex);
|
||||
//@}
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Simple exception thrown to indicate an error in the input SRecord data format.
|
||||
*/
|
||||
class StSRecordParseException : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
//! \brief Default constructor.
|
||||
StSRecordParseException(const std::string &inMessage)
|
||||
: std::runtime_error(inMessage)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
#endif // _StSRecordFile_h_
|
||||
60
apps/elftosb/common/StringMatcher.h
Normal file
60
apps/elftosb/common/StringMatcher.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* File: GlobSectionSelector.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
#if !defined(_StringMatcher_h_)
|
||||
#define _StringMatcher_h_
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace elftosb
|
||||
{
|
||||
/*!
|
||||
* \brief Abstract interface class used to select strings by name.
|
||||
*/
|
||||
class StringMatcher
|
||||
{
|
||||
public:
|
||||
//! \brief Performs a single string match test against testValue.
|
||||
//!
|
||||
//! \retval true The \a testValue argument matches.
|
||||
//! \retval false No match was made against the argument.
|
||||
virtual bool match(const std::string &testValue) = 0;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief String matcher subclass that matches all test strings.
|
||||
*/
|
||||
class WildcardMatcher : public StringMatcher
|
||||
{
|
||||
public:
|
||||
//! \brief Always returns true, indicating a positive match.
|
||||
virtual bool match(const std::string &testValue) { return true; }
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Simple string matcher that compares against a fixed value.
|
||||
*/
|
||||
class FixedMatcher : public StringMatcher
|
||||
{
|
||||
public:
|
||||
//! \brief Constructor. Sets the string to compare against to be \a fixedValue.
|
||||
FixedMatcher(const std::string &fixedValue)
|
||||
: m_value(fixedValue)
|
||||
{
|
||||
}
|
||||
|
||||
//! \brief Returns whether \a testValue is the same as the value passed to the constructor.
|
||||
//!
|
||||
//! \retval true The \a testValue argument matches the fixed compare value.
|
||||
//! \retval false The argument is not the same as the compare value.
|
||||
virtual bool match(const std::string &testValue) { return testValue == m_value; }
|
||||
protected:
|
||||
const std::string &m_value; //!< The section name to look for.
|
||||
};
|
||||
|
||||
}; // namespace elftosb
|
||||
|
||||
#endif // _StringMatcher_h_
|
||||
42
apps/elftosb/common/Value.cpp
Normal file
42
apps/elftosb/common/Value.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* File: Value.cpp
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
|
||||
#include "Value.h"
|
||||
|
||||
using namespace elftosb;
|
||||
|
||||
//! Returns a varying size depending on the word size attribute.
|
||||
//!
|
||||
size_t SizedIntegerValue::getSize() const
|
||||
{
|
||||
switch (m_size)
|
||||
{
|
||||
case kWordSize:
|
||||
return sizeof(uint32_t);
|
||||
case kHalfWordSize:
|
||||
return sizeof(uint16_t);
|
||||
case kByteSize:
|
||||
return sizeof(uint8_t);
|
||||
}
|
||||
return kWordSize;
|
||||
}
|
||||
|
||||
//! The resulting mask can be used to truncate the integer value to be
|
||||
//! certain it doesn't extend beyond the associated word size.
|
||||
uint32_t SizedIntegerValue::getWordSizeMask() const
|
||||
{
|
||||
switch (m_size)
|
||||
{
|
||||
case kWordSize:
|
||||
return 0xffffffff;
|
||||
case kHalfWordSize:
|
||||
return 0x0000ffff;
|
||||
case kByteSize:
|
||||
return 0x000000ff;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
206
apps/elftosb/common/Value.h
Normal file
206
apps/elftosb/common/Value.h
Normal file
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* File: Value.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
#if !defined(_Value_h_)
|
||||
#define _Value_h_
|
||||
|
||||
#include "stdafx.h"
|
||||
#include <string>
|
||||
#include "int_size.h"
|
||||
#include "Blob.h"
|
||||
|
||||
namespace elftosb
|
||||
{
|
||||
/*!
|
||||
* \brief Abstract base class for values of arbitrary types.
|
||||
*/
|
||||
class Value
|
||||
{
|
||||
public:
|
||||
Value() {}
|
||||
virtual ~Value() {}
|
||||
virtual std::string getTypeName() const = 0;
|
||||
virtual size_t getSize() const = 0;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief 32-bit signed integer value.
|
||||
*/
|
||||
class IntegerValue : public Value
|
||||
{
|
||||
public:
|
||||
IntegerValue()
|
||||
: m_value(0)
|
||||
{
|
||||
}
|
||||
IntegerValue(uint32_t value)
|
||||
: m_value(value)
|
||||
{
|
||||
}
|
||||
IntegerValue(const IntegerValue &other)
|
||||
: m_value(other.m_value)
|
||||
{
|
||||
}
|
||||
|
||||
virtual std::string getTypeName() const { return "integer"; }
|
||||
virtual size_t getSize() const { return sizeof(m_value); }
|
||||
inline uint32_t getValue() const { return m_value; }
|
||||
inline operator uint32_t() const { return m_value; }
|
||||
inline IntegerValue &operator=(uint32_t value)
|
||||
{
|
||||
m_value = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
uint32_t m_value; //!< The integer value.
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Adds a word size attribute to IntegerValue.
|
||||
*
|
||||
* The word size really only acts as an attribute that is carried along
|
||||
* with the integer value. It doesn't affect the actual value at all.
|
||||
* However, you can use the getWordSizeMask() method to mask off bits
|
||||
* that should not be there.
|
||||
*
|
||||
* The word size defaults to a 32-bit word.
|
||||
*/
|
||||
class SizedIntegerValue : public IntegerValue
|
||||
{
|
||||
public:
|
||||
SizedIntegerValue()
|
||||
: IntegerValue()
|
||||
, m_size(kWordSize)
|
||||
{
|
||||
}
|
||||
SizedIntegerValue(uint32_t value, int_size_t size = kWordSize)
|
||||
: IntegerValue(value)
|
||||
, m_size(size)
|
||||
{
|
||||
}
|
||||
SizedIntegerValue(uint16_t value)
|
||||
: IntegerValue(value)
|
||||
, m_size(kHalfWordSize)
|
||||
{
|
||||
}
|
||||
SizedIntegerValue(uint8_t value)
|
||||
: IntegerValue(value)
|
||||
, m_size(kByteSize)
|
||||
{
|
||||
}
|
||||
SizedIntegerValue(const SizedIntegerValue &other)
|
||||
: IntegerValue(other)
|
||||
, m_size(other.m_size)
|
||||
{
|
||||
}
|
||||
|
||||
virtual std::string getTypeName() const { return "sized integer"; }
|
||||
virtual size_t getSize() const;
|
||||
|
||||
inline int_size_t getWordSize() const { return m_size; }
|
||||
inline void setWordSize(int_size_t size) { m_size = size; }
|
||||
//! \brief Returns a 32-bit mask value dependant on the word size attribute.
|
||||
uint32_t getWordSizeMask() const;
|
||||
|
||||
//! \name Assignment operators
|
||||
//! These operators set the word size as well as the integer value.
|
||||
//@{
|
||||
SizedIntegerValue &operator=(uint8_t value)
|
||||
{
|
||||
m_value = value;
|
||||
m_size = kByteSize;
|
||||
return *this;
|
||||
}
|
||||
SizedIntegerValue &operator=(uint16_t value)
|
||||
{
|
||||
m_value = value;
|
||||
m_size = kHalfWordSize;
|
||||
return *this;
|
||||
}
|
||||
SizedIntegerValue &operator=(uint32_t value)
|
||||
{
|
||||
m_value = value;
|
||||
m_size = kWordSize;
|
||||
return *this;
|
||||
}
|
||||
//@}
|
||||
|
||||
protected:
|
||||
int_size_t m_size; //!< Size of the integer.
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief String value.
|
||||
*
|
||||
* Simply wraps the STL std::string class.
|
||||
*/
|
||||
class StringValue : public Value
|
||||
{
|
||||
public:
|
||||
StringValue()
|
||||
: m_value()
|
||||
{
|
||||
}
|
||||
StringValue(const std::string &value)
|
||||
: m_value(value)
|
||||
{
|
||||
}
|
||||
StringValue(const std::string *value)
|
||||
: m_value(*value)
|
||||
{
|
||||
}
|
||||
StringValue(const StringValue &other)
|
||||
: m_value(other.m_value)
|
||||
{
|
||||
}
|
||||
|
||||
virtual std::string getTypeName() const { return "string"; }
|
||||
virtual size_t getSize() const { return m_value.size(); }
|
||||
operator const char *() const { return m_value.c_str(); }
|
||||
operator const std::string &() const { return m_value; }
|
||||
operator std::string &() { return m_value; }
|
||||
operator const std::string *() { return &m_value; }
|
||||
operator std::string *() { return &m_value; }
|
||||
StringValue &operator=(const StringValue &other)
|
||||
{
|
||||
m_value = other.m_value;
|
||||
return *this;
|
||||
}
|
||||
StringValue &operator=(const std::string &value)
|
||||
{
|
||||
m_value = value;
|
||||
return *this;
|
||||
}
|
||||
StringValue &operator=(const char *value)
|
||||
{
|
||||
m_value = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
std::string m_value;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Binary object value of arbitrary size.
|
||||
*/
|
||||
class BinaryValue : public Value, public Blob
|
||||
{
|
||||
public:
|
||||
BinaryValue()
|
||||
: Value()
|
||||
, Blob()
|
||||
{
|
||||
}
|
||||
|
||||
virtual std::string getTypeName() const { return "binary"; }
|
||||
virtual size_t getSize() const { return getLength(); }
|
||||
};
|
||||
|
||||
}; // namespace elftosb
|
||||
|
||||
#endif // _Value_h_
|
||||
143
apps/elftosb/common/Version.cpp
Normal file
143
apps/elftosb/common/Version.cpp
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* File: Version.cpp
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
|
||||
#include "Version.h"
|
||||
#include "EndianUtilities.h"
|
||||
|
||||
using namespace elftosb;
|
||||
|
||||
/*!
|
||||
* Parses a string in the form "xxx.xxx.xxx" (where x is a digit) into
|
||||
* three version fields for major, minor, and revision. The output is
|
||||
* right aligned BCD in host-natural byte order.
|
||||
*
|
||||
* \param versionString String containing the version.
|
||||
*/
|
||||
void version_t::set(const std::string &versionString)
|
||||
{
|
||||
size_t length = versionString.size();
|
||||
unsigned version = 0;
|
||||
unsigned index = 0;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
kVersionStateNone,
|
||||
kVersionStateMajor,
|
||||
kVersionStateMinor,
|
||||
kVersionStateRevision
|
||||
} VersionParseState;
|
||||
|
||||
// set initial versions to 0s
|
||||
m_major = 0;
|
||||
m_minor = 0;
|
||||
m_revision = 0;
|
||||
|
||||
VersionParseState parseState = kVersionStateNone;
|
||||
bool done = false;
|
||||
for (; index < length && !done; ++index)
|
||||
{
|
||||
char c = versionString[index];
|
||||
|
||||
if (isdigit(c))
|
||||
{
|
||||
switch (parseState)
|
||||
{
|
||||
case kVersionStateNone:
|
||||
parseState = kVersionStateMajor;
|
||||
version = c - '0';
|
||||
break;
|
||||
case kVersionStateMajor:
|
||||
case kVersionStateMinor:
|
||||
case kVersionStateRevision:
|
||||
version = (version << 4) | (c - '0');
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (c == '.')
|
||||
{
|
||||
switch (parseState)
|
||||
{
|
||||
case kVersionStateNone:
|
||||
parseState = kVersionStateNone;
|
||||
break;
|
||||
case kVersionStateMajor:
|
||||
m_major = version;
|
||||
version = 0;
|
||||
parseState = kVersionStateMinor;
|
||||
break;
|
||||
case kVersionStateMinor:
|
||||
m_minor = version;
|
||||
version = 0;
|
||||
parseState = kVersionStateRevision;
|
||||
break;
|
||||
case kVersionStateRevision:
|
||||
m_revision = version;
|
||||
version = 0;
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (parseState)
|
||||
{
|
||||
case kVersionStateNone:
|
||||
parseState = kVersionStateNone;
|
||||
break;
|
||||
case kVersionStateMajor:
|
||||
m_major = version;
|
||||
done = true;
|
||||
break;
|
||||
case kVersionStateMinor:
|
||||
m_minor = version;
|
||||
done = true;
|
||||
break;
|
||||
case kVersionStateRevision:
|
||||
m_revision = version;
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (parseState)
|
||||
{
|
||||
case kVersionStateMajor:
|
||||
m_major = version;
|
||||
break;
|
||||
case kVersionStateMinor:
|
||||
m_minor = version;
|
||||
break;
|
||||
case kVersionStateRevision:
|
||||
m_revision = version;
|
||||
break;
|
||||
default:
|
||||
// do nothing
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//! \brief Converts host endian BCD version values to the equivalent big-endian BCD values.
|
||||
//!
|
||||
//! The output is a half-word. And BCD is inherently big-endian, or byte ordered, if
|
||||
//! you prefer to think of it that way. So for little endian systems, we need to convert
|
||||
//! the output half-word in reverse byte order. When it is written to disk or a
|
||||
//! buffer it will come out big endian.
|
||||
//!
|
||||
//! For example:
|
||||
//! - The input is BCD in host endian format, so 0x1234. Written to a file, this would
|
||||
//! come out as 0x34 0x12, reverse of what we want.
|
||||
//! - The desired BCD output is the two bytes 0x12 0x34.
|
||||
//! - So the function's uint16_t result must be 0x3412 on a little-endian host.
|
||||
//!
|
||||
//! On big endian hosts, we don't have to worry about byte swapping.
|
||||
void version_t::fixByteOrder()
|
||||
{
|
||||
m_major = ENDIAN_HOST_TO_BIG_U16(m_major);
|
||||
m_minor = ENDIAN_HOST_TO_BIG_U16(m_minor);
|
||||
m_revision = ENDIAN_HOST_TO_BIG_U16(m_revision);
|
||||
}
|
||||
65
apps/elftosb/common/Version.h
Normal file
65
apps/elftosb/common/Version.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* File: Version.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
#if !defined(_Version_h_)
|
||||
#define _Version_h_
|
||||
|
||||
#include <string>
|
||||
#include "stdafx.h"
|
||||
|
||||
namespace elftosb
|
||||
{
|
||||
//! Same version struct used for 3600 boot image.
|
||||
struct version_t
|
||||
{
|
||||
uint16_t m_major;
|
||||
uint16_t m_pad0;
|
||||
uint16_t m_minor;
|
||||
uint16_t m_pad1;
|
||||
uint16_t m_revision;
|
||||
uint16_t m_pad2;
|
||||
|
||||
version_t()
|
||||
: m_major(0x999)
|
||||
, m_pad0(0)
|
||||
, m_minor(0x999)
|
||||
, m_pad1(0)
|
||||
, m_revision(0x999)
|
||||
, m_pad2(0)
|
||||
{
|
||||
}
|
||||
|
||||
version_t(uint16_t maj, uint16_t min, uint16_t rev)
|
||||
: m_major(maj)
|
||||
, m_pad0(0)
|
||||
, m_minor(min)
|
||||
, m_pad1(0)
|
||||
, m_revision(rev)
|
||||
, m_pad2(0)
|
||||
{
|
||||
}
|
||||
|
||||
version_t(const std::string &versionString)
|
||||
: m_major(0x999)
|
||||
, m_pad0(0)
|
||||
, m_minor(0x999)
|
||||
, m_pad1(0)
|
||||
, m_revision(0x999)
|
||||
, m_pad2(0)
|
||||
{
|
||||
set(versionString);
|
||||
}
|
||||
|
||||
//! \brief Sets the version by parsing a string.
|
||||
void set(const std::string &versionString);
|
||||
|
||||
//! \brief
|
||||
void fixByteOrder();
|
||||
};
|
||||
|
||||
}; // namespace elftosb
|
||||
|
||||
#endif // _Version_h_
|
||||
309
apps/elftosb/common/aes128_key_wrap_unwrap.c
Normal file
309
apps/elftosb/common/aes128_key_wrap_unwrap.c
Normal file
@@ -0,0 +1,309 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Freescale Semiconductor, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* o Redistributions of source code must retain the above copyright notice, this list
|
||||
* of conditions and the following disclaimer.
|
||||
*
|
||||
* o Redistributions in binary form must reproduce the above copyright notice, this
|
||||
* list of conditions and the following disclaimer in the documentation and/or
|
||||
* other materials provided with the distribution.
|
||||
*
|
||||
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#define BOOTLOADER_HOST
|
||||
|
||||
#include "aes128_key_wrap_unwrap.h"
|
||||
#if !defined(BOOTLOADER_HOST)
|
||||
#include "security/aes_security.h"
|
||||
#endif
|
||||
|
||||
#if defined(BOOTLOADER_HOST)
|
||||
// From bytes_aes.c.
|
||||
extern void Cipher(unsigned char cin[], unsigned int w[], int nr, unsigned char cout[]);
|
||||
extern void InvCipher(unsigned char cin[], unsigned int w[], int nr, unsigned char cout[]);
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Definitions
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//! @brief number of 64-bit data blocks
|
||||
#define N 5
|
||||
|
||||
//! @brief 64-bit initialization vector
|
||||
static const unsigned char iv[8] = { 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6 };
|
||||
//! @brief 64-bit integrity check register
|
||||
static unsigned char a[8];
|
||||
//! @brief 8-bit array of 64-bit registers
|
||||
static unsigned char r[8 * (N + 1)];
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Code
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// See aes128_key_wrap_unwrap.h for documentation on this function.
|
||||
void do_aes128_key_wrap(const unsigned char plaintext[],
|
||||
unsigned char wrapped_ciphertext[],
|
||||
unsigned int expanded_kek[])
|
||||
{
|
||||
unsigned int i, j; // loop counters
|
||||
unsigned char in[16]; // 128-bit temporary plaintext input vector
|
||||
|
||||
// step 1: initialize the byte-sized data variables
|
||||
// set A = IV
|
||||
// for i = 1 to n
|
||||
// R[i] = P[i]
|
||||
|
||||
a[0] = iv[0];
|
||||
a[1] = iv[1];
|
||||
a[2] = iv[2];
|
||||
a[3] = iv[3];
|
||||
a[4] = iv[4];
|
||||
a[5] = iv[5];
|
||||
a[6] = iv[6];
|
||||
a[7] = iv[7];
|
||||
|
||||
for (i = 1; i <= N; i++)
|
||||
{
|
||||
r[8 * i + 0] = plaintext[8 * (i - 1) + 0];
|
||||
r[8 * i + 1] = plaintext[8 * (i - 1) + 1];
|
||||
r[8 * i + 2] = plaintext[8 * (i - 1) + 2];
|
||||
r[8 * i + 3] = plaintext[8 * (i - 1) + 3];
|
||||
r[8 * i + 4] = plaintext[8 * (i - 1) + 4];
|
||||
r[8 * i + 5] = plaintext[8 * (i - 1) + 5];
|
||||
r[8 * i + 6] = plaintext[8 * (i - 1) + 6];
|
||||
r[8 * i + 7] = plaintext[8 * (i - 1) + 7];
|
||||
}
|
||||
|
||||
// step 2: calculate intermediate values
|
||||
// for j = 0 to 5
|
||||
// for i = 1 to n
|
||||
// B = AES(K, A | R[i])
|
||||
// A = MSB(64, B) ^ (n*j)+i
|
||||
// R[i] = LSB(64, B)
|
||||
|
||||
for (j = 0; j <= 5; j++)
|
||||
{
|
||||
for (i = 1; i <= N; i++)
|
||||
{
|
||||
in[0] = a[0];
|
||||
in[1] = a[1];
|
||||
in[2] = a[2];
|
||||
in[3] = a[3];
|
||||
in[4] = a[4];
|
||||
in[5] = a[5];
|
||||
in[6] = a[6];
|
||||
in[7] = a[7];
|
||||
|
||||
in[8] = r[8 * i + 0];
|
||||
in[9] = r[8 * i + 1];
|
||||
in[10] = r[8 * i + 2];
|
||||
in[11] = r[8 * i + 3];
|
||||
in[12] = r[8 * i + 4];
|
||||
in[13] = r[8 * i + 5];
|
||||
in[14] = r[8 * i + 6];
|
||||
in[15] = r[8 * i + 7];
|
||||
|
||||
#if defined BOOTLOADER_HOST
|
||||
Cipher(in, expanded_kek, 10, in); // perform aes128 encryption
|
||||
#else
|
||||
aes_encrypt((unsigned int *)in, expanded_kek, (unsigned int *)in);
|
||||
#endif // BOOTLOADER_HOST
|
||||
|
||||
a[0] = in[0];
|
||||
a[1] = in[1];
|
||||
a[2] = in[2];
|
||||
a[3] = in[3];
|
||||
a[4] = in[4];
|
||||
a[5] = in[5];
|
||||
a[6] = in[6];
|
||||
a[7] = in[7] ^ ((N * j) + i);
|
||||
|
||||
r[8 * i + 0] = in[8];
|
||||
r[8 * i + 1] = in[9];
|
||||
r[8 * i + 2] = in[10];
|
||||
r[8 * i + 3] = in[11];
|
||||
r[8 * i + 4] = in[12];
|
||||
r[8 * i + 5] = in[13];
|
||||
r[8 * i + 6] = in[14];
|
||||
r[8 * i + 7] = in[15];
|
||||
} // end for (i)
|
||||
} // end for (j)
|
||||
|
||||
// step 3: output the results
|
||||
// set C[0] = A
|
||||
// for i = 1 to n
|
||||
// C[i] = R[i]
|
||||
|
||||
wrapped_ciphertext[0] = a[0];
|
||||
wrapped_ciphertext[1] = a[1];
|
||||
wrapped_ciphertext[2] = a[2];
|
||||
wrapped_ciphertext[3] = a[3];
|
||||
wrapped_ciphertext[4] = a[4];
|
||||
wrapped_ciphertext[5] = a[5];
|
||||
wrapped_ciphertext[6] = a[6];
|
||||
wrapped_ciphertext[7] = a[7];
|
||||
|
||||
for (i = 1; i <= N; i++)
|
||||
{
|
||||
wrapped_ciphertext[8 * i + 0] = r[8 * i + 0];
|
||||
wrapped_ciphertext[8 * i + 1] = r[8 * i + 1];
|
||||
wrapped_ciphertext[8 * i + 2] = r[8 * i + 2];
|
||||
wrapped_ciphertext[8 * i + 3] = r[8 * i + 3];
|
||||
wrapped_ciphertext[8 * i + 4] = r[8 * i + 4];
|
||||
wrapped_ciphertext[8 * i + 5] = r[8 * i + 5];
|
||||
wrapped_ciphertext[8 * i + 6] = r[8 * i + 6];
|
||||
wrapped_ciphertext[8 * i + 7] = r[8 * i + 7];
|
||||
}
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
//******************************************************************************
|
||||
|
||||
// See aes128_key_wrap_unwrap.h for documentation on this function.
|
||||
unsigned int do_aes128_key_unwrap(const unsigned char wrapped_ciphertext[],
|
||||
unsigned char unwrapped_plaintext[],
|
||||
unsigned int expanded_kek[])
|
||||
{
|
||||
signed int i, j; // loop counters
|
||||
unsigned char in[16]; // 128-bit temporary ciphertext input vector
|
||||
|
||||
// step 1: initialize variables
|
||||
// set A = C[0]
|
||||
// for i = 1 to n
|
||||
// R[i] = C[i]
|
||||
|
||||
a[0] = wrapped_ciphertext[0];
|
||||
a[1] = wrapped_ciphertext[1];
|
||||
a[2] = wrapped_ciphertext[2];
|
||||
a[3] = wrapped_ciphertext[3];
|
||||
a[4] = wrapped_ciphertext[4];
|
||||
a[5] = wrapped_ciphertext[5];
|
||||
a[6] = wrapped_ciphertext[6];
|
||||
a[7] = wrapped_ciphertext[7];
|
||||
|
||||
for (i = 1; i <= N; i++)
|
||||
{
|
||||
r[8 * i + 0] = wrapped_ciphertext[8 * i + 0];
|
||||
r[8 * i + 1] = wrapped_ciphertext[8 * i + 1];
|
||||
r[8 * i + 2] = wrapped_ciphertext[8 * i + 2];
|
||||
r[8 * i + 3] = wrapped_ciphertext[8 * i + 3];
|
||||
r[8 * i + 4] = wrapped_ciphertext[8 * i + 4];
|
||||
r[8 * i + 5] = wrapped_ciphertext[8 * i + 5];
|
||||
r[8 * i + 6] = wrapped_ciphertext[8 * i + 6];
|
||||
r[8 * i + 7] = wrapped_ciphertext[8 * i + 7];
|
||||
}
|
||||
|
||||
// step 2: calculate intermediate values
|
||||
// for j = 5 to 0
|
||||
// for i = n to 1
|
||||
// B = AES-1(K, (A ^ (n*j+i) | R[i])
|
||||
// A = MSB(64, B)
|
||||
// R[i] = LSB(64, B)
|
||||
|
||||
for (j = 5; j >= 0; j--)
|
||||
{
|
||||
for (i = N; i >= 1; i--)
|
||||
{
|
||||
in[0] = a[0];
|
||||
in[1] = a[1];
|
||||
in[2] = a[2];
|
||||
in[3] = a[3];
|
||||
in[4] = a[4];
|
||||
in[5] = a[5];
|
||||
in[6] = a[6];
|
||||
in[7] = a[7] ^ ((N * j) + i);
|
||||
|
||||
in[8] = r[8 * i + 0];
|
||||
in[9] = r[8 * i + 1];
|
||||
in[10] = r[8 * i + 2];
|
||||
in[11] = r[8 * i + 3];
|
||||
in[12] = r[8 * i + 4];
|
||||
in[13] = r[8 * i + 5];
|
||||
in[14] = r[8 * i + 6];
|
||||
in[15] = r[8 * i + 7];
|
||||
|
||||
#if defined BOOTLOADER_HOST
|
||||
InvCipher(in, expanded_kek, 10, in); // perform aes128 decryption
|
||||
#else
|
||||
// TODO aes_decrypt reverses bytes(?)
|
||||
aes_decrypt((unsigned int *)in, expanded_kek, (unsigned int *)in);
|
||||
#endif // BOOTLOADER_HOST
|
||||
|
||||
a[0] = in[0];
|
||||
a[1] = in[1];
|
||||
a[2] = in[2];
|
||||
a[3] = in[3];
|
||||
a[4] = in[4];
|
||||
a[5] = in[5];
|
||||
a[6] = in[6];
|
||||
a[7] = in[7];
|
||||
|
||||
r[8 * i + 0] = in[8];
|
||||
r[8 * i + 1] = in[9];
|
||||
r[8 * i + 2] = in[10];
|
||||
r[8 * i + 3] = in[11];
|
||||
r[8 * i + 4] = in[12];
|
||||
r[8 * i + 5] = in[13];
|
||||
r[8 * i + 6] = in[14];
|
||||
r[8 * i + 7] = in[15];
|
||||
} // end for (i)
|
||||
} // end for (j)
|
||||
|
||||
// step 3: output the results
|
||||
// if A == IV
|
||||
// then
|
||||
// for i = 1 to n
|
||||
// P[i] = R[i]
|
||||
// else
|
||||
// return an error
|
||||
|
||||
unwrapped_plaintext[0] = a[0];
|
||||
unwrapped_plaintext[1] = a[1];
|
||||
unwrapped_plaintext[2] = a[2];
|
||||
unwrapped_plaintext[3] = a[3];
|
||||
unwrapped_plaintext[4] = a[4];
|
||||
unwrapped_plaintext[5] = a[5];
|
||||
unwrapped_plaintext[6] = a[6];
|
||||
unwrapped_plaintext[7] = a[7];
|
||||
|
||||
for (i = 1; i <= N; i++)
|
||||
{
|
||||
unwrapped_plaintext[8 * i + 0] = r[8 * i + 0];
|
||||
unwrapped_plaintext[8 * i + 1] = r[8 * i + 1];
|
||||
unwrapped_plaintext[8 * i + 2] = r[8 * i + 2];
|
||||
unwrapped_plaintext[8 * i + 3] = r[8 * i + 3];
|
||||
unwrapped_plaintext[8 * i + 4] = r[8 * i + 4];
|
||||
unwrapped_plaintext[8 * i + 5] = r[8 * i + 5];
|
||||
unwrapped_plaintext[8 * i + 6] = r[8 * i + 6];
|
||||
unwrapped_plaintext[8 * i + 7] = r[8 * i + 7];
|
||||
}
|
||||
|
||||
if ((unwrapped_plaintext[0] == iv[0]) && (unwrapped_plaintext[1] == iv[1]) && (unwrapped_plaintext[2] == iv[2]) &&
|
||||
(unwrapped_plaintext[3] == iv[3]) && (unwrapped_plaintext[4] == iv[4]) && (unwrapped_plaintext[5] == iv[5]) &&
|
||||
(unwrapped_plaintext[6] == iv[6]) && (unwrapped_plaintext[7] == iv[7]))
|
||||
return 0; // error-free exit
|
||||
else
|
||||
return -1; // error exit
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// EOF
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
80
apps/elftosb/common/aes128_key_wrap_unwrap.h
Normal file
80
apps/elftosb/common/aes128_key_wrap_unwrap.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Freescale Semiconductor, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* o Redistributions of source code must retain the above copyright notice, this list
|
||||
* of conditions and the following disclaimer.
|
||||
*
|
||||
* o Redistributions in binary form must reproduce the above copyright notice, this
|
||||
* list of conditions and the following disclaimer in the documentation and/or
|
||||
* other materials provided with the distribution.
|
||||
*
|
||||
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _aes128_key_wrap_unwrap_h
|
||||
#define _aes128_key_wrap_unwrap_h
|
||||
|
||||
//! @addtogroup aes_key_wrap
|
||||
//! @{
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// API
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//! @name aes_key_wrap
|
||||
//@{
|
||||
|
||||
//! @brief Encrypt and wrap plaintext key.
|
||||
//!
|
||||
//! @param plaintext 40 byte plaintext input array
|
||||
//! @param wrapped_ciphertext 48 byte wrapped output array
|
||||
//! @param expanded_kek Expanded kek (64 bytes)
|
||||
void do_aes128_key_wrap(const unsigned char plaintext[],
|
||||
unsigned char wrapped_ciphertext[],
|
||||
unsigned int expanded_kek[]);
|
||||
|
||||
//! @brief Decrypt and unwrap wrapped key.
|
||||
//!
|
||||
//! @param wrapped_ciphertext 48 byte wrapped input array
|
||||
//! @param unwrapped_plaintext 48 byte plaintext output array, Note: this includes an 8 byte IV header
|
||||
//! that is added to start of the original 40 input bytes by the wrapping
|
||||
//! @param expanded_kek Expanded kek (64 ints on host, 4 ints on device)
|
||||
//! @retval -1 on error
|
||||
//! @retval 0 on success
|
||||
unsigned int do_aes128_key_unwrap(const unsigned char wrapped_ciphertext[],
|
||||
unsigned char unwrapped_plaintext[],
|
||||
unsigned int expanded_kek[]);
|
||||
//@}
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
//! @}
|
||||
|
||||
#endif // _aes128_key_wrap_unwrap_h
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// EOF
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
432
apps/elftosb/common/bytes_aes.c
Normal file
432
apps/elftosb/common/bytes_aes.c
Normal file
@@ -0,0 +1,432 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Freescale Semiconductor, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* o Redistributions of source code must retain the above copyright notice, this list
|
||||
* of conditions and the following disclaimer.
|
||||
*
|
||||
* o Redistributions in binary form must reproduce the above copyright notice, this
|
||||
* list of conditions and the following disclaimer in the documentation and/or
|
||||
* other materials provided with the distribution.
|
||||
*
|
||||
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// Advanced Encryption Standard
|
||||
#ifdef DEBUG
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#define SubBytes(i) (Sbox[(i) >> 24] << 24 | Sbox[(i) >> 16 & 0xff] << 16 | Sbox[(i) >> 8 & 0xff] << 8 | Sbox[(i)&0xff])
|
||||
|
||||
#define InvSubBytes(i) \
|
||||
(InvSbox[(i) >> 24] << 24 | InvSbox[(i) >> 16 & 0xff] << 16 | InvSbox[(i) >> 8 & 0xff] << 8 | InvSbox[(i)&0xff])
|
||||
|
||||
static unsigned char Sbox[] = {
|
||||
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9,
|
||||
0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f,
|
||||
0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07,
|
||||
0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3,
|
||||
0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58,
|
||||
0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3,
|
||||
0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f,
|
||||
0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
|
||||
0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac,
|
||||
0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a,
|
||||
0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70,
|
||||
0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11,
|
||||
0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42,
|
||||
0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
|
||||
};
|
||||
|
||||
static unsigned char InvSbox[] = {
|
||||
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39,
|
||||
0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2,
|
||||
0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76,
|
||||
0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc,
|
||||
0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d,
|
||||
0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c,
|
||||
0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41, 0x4f,
|
||||
0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85,
|
||||
0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62,
|
||||
0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd,
|
||||
0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60,
|
||||
0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d,
|
||||
0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6,
|
||||
0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
|
||||
};
|
||||
|
||||
static unsigned char x2[] = {
|
||||
0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x22, 0x24,
|
||||
0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e, 0x40, 0x42, 0x44, 0x46, 0x48, 0x4a,
|
||||
0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70,
|
||||
0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e, 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96,
|
||||
0x98, 0x9a, 0x9c, 0x9e, 0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc,
|
||||
0xbe, 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2,
|
||||
0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe, 0x1b, 0x19, 0x1f, 0x1d, 0x13,
|
||||
0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05, 0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35,
|
||||
0x2b, 0x29, 0x2f, 0x2d, 0x23, 0x21, 0x27, 0x25, 0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55, 0x4b, 0x49, 0x4f,
|
||||
0x4d, 0x43, 0x41, 0x47, 0x45, 0x7b, 0x79, 0x7f, 0x7d, 0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61,
|
||||
0x67, 0x65, 0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d, 0x83, 0x81, 0x87, 0x85, 0xbb,
|
||||
0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5, 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5, 0xdb, 0xd9, 0xdf, 0xdd,
|
||||
0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5, 0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7,
|
||||
0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5
|
||||
};
|
||||
|
||||
static unsigned char x3[] = {
|
||||
0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11, 0x30, 0x33, 0x36,
|
||||
0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21, 0x60, 0x63, 0x66, 0x65, 0x6c, 0x6f,
|
||||
0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71, 0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59, 0x48,
|
||||
0x4b, 0x4e, 0x4d, 0x44, 0x47, 0x42, 0x41, 0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9, 0xd8, 0xdb, 0xde, 0xdd,
|
||||
0xd4, 0xd7, 0xd2, 0xd1, 0xf0, 0xf3, 0xf6, 0xf5, 0xfc, 0xff, 0xfa, 0xf9, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2,
|
||||
0xe1, 0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9, 0xb8, 0xbb, 0xbe, 0xbd, 0xb4, 0xb7, 0xb2, 0xb1, 0x90, 0x93,
|
||||
0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99, 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81, 0x9b, 0x98, 0x9d, 0x9e, 0x97,
|
||||
0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89, 0x8a, 0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2,
|
||||
0xb3, 0xb0, 0xb5, 0xb6, 0xbf, 0xbc, 0xb9, 0xba, 0xfb, 0xf8, 0xfd, 0xfe, 0xf7, 0xf4, 0xf1, 0xf2, 0xe3, 0xe0, 0xe5,
|
||||
0xe6, 0xef, 0xec, 0xe9, 0xea, 0xcb, 0xc8, 0xcd, 0xce, 0xc7, 0xc4, 0xc1, 0xc2, 0xd3, 0xd0, 0xd5, 0xd6, 0xdf, 0xdc,
|
||||
0xd9, 0xda, 0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46, 0x4f, 0x4c, 0x49, 0x4a, 0x6b,
|
||||
0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62, 0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a, 0x3b, 0x38, 0x3d, 0x3e,
|
||||
0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a, 0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01,
|
||||
0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a
|
||||
};
|
||||
|
||||
static unsigned char x9[] = {
|
||||
0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77, 0x90, 0x99, 0x82,
|
||||
0x8b, 0xb4, 0xbd, 0xa6, 0xaf, 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7, 0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16,
|
||||
0x0d, 0x04, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c, 0xab, 0xa2, 0xb9, 0xb0, 0x8f, 0x86, 0x9d, 0x94, 0xe3,
|
||||
0xea, 0xf1, 0xf8, 0xc7, 0xce, 0xd5, 0xdc, 0x76, 0x7f, 0x64, 0x6d, 0x52, 0x5b, 0x40, 0x49, 0x3e, 0x37, 0x2c, 0x25,
|
||||
0x1a, 0x13, 0x08, 0x01, 0xe6, 0xef, 0xf4, 0xfd, 0xc2, 0xcb, 0xd0, 0xd9, 0xae, 0xa7, 0xbc, 0xb5, 0x8a, 0x83, 0x98,
|
||||
0x91, 0x4d, 0x44, 0x5f, 0x56, 0x69, 0x60, 0x7b, 0x72, 0x05, 0x0c, 0x17, 0x1e, 0x21, 0x28, 0x33, 0x3a, 0xdd, 0xd4,
|
||||
0xcf, 0xc6, 0xf9, 0xf0, 0xeb, 0xe2, 0x95, 0x9c, 0x87, 0x8e, 0xb1, 0xb8, 0xa3, 0xaa, 0xec, 0xe5, 0xfe, 0xf7, 0xc8,
|
||||
0xc1, 0xda, 0xd3, 0xa4, 0xad, 0xb6, 0xbf, 0x80, 0x89, 0x92, 0x9b, 0x7c, 0x75, 0x6e, 0x67, 0x58, 0x51, 0x4a, 0x43,
|
||||
0x34, 0x3d, 0x26, 0x2f, 0x10, 0x19, 0x02, 0x0b, 0xd7, 0xde, 0xc5, 0xcc, 0xf3, 0xfa, 0xe1, 0xe8, 0x9f, 0x96, 0x8d,
|
||||
0x84, 0xbb, 0xb2, 0xa9, 0xa0, 0x47, 0x4e, 0x55, 0x5c, 0x63, 0x6a, 0x71, 0x78, 0x0f, 0x06, 0x1d, 0x14, 0x2b, 0x22,
|
||||
0x39, 0x30, 0x9a, 0x93, 0x88, 0x81, 0xbe, 0xb7, 0xac, 0xa5, 0xd2, 0xdb, 0xc0, 0xc9, 0xf6, 0xff, 0xe4, 0xed, 0x0a,
|
||||
0x03, 0x18, 0x11, 0x2e, 0x27, 0x3c, 0x35, 0x42, 0x4b, 0x50, 0x59, 0x66, 0x6f, 0x74, 0x7d, 0xa1, 0xa8, 0xb3, 0xba,
|
||||
0x85, 0x8c, 0x97, 0x9e, 0xe9, 0xe0, 0xfb, 0xf2, 0xcd, 0xc4, 0xdf, 0xd6, 0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07,
|
||||
0x0e, 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46
|
||||
};
|
||||
|
||||
static unsigned char xb[] = {
|
||||
0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69, 0xb0, 0xbb, 0xa6,
|
||||
0xad, 0x9c, 0x97, 0x8a, 0x81, 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9, 0x7b, 0x70, 0x6d, 0x66, 0x57, 0x5c,
|
||||
0x41, 0x4a, 0x23, 0x28, 0x35, 0x3e, 0x0f, 0x04, 0x19, 0x12, 0xcb, 0xc0, 0xdd, 0xd6, 0xe7, 0xec, 0xf1, 0xfa, 0x93,
|
||||
0x98, 0x85, 0x8e, 0xbf, 0xb4, 0xa9, 0xa2, 0xf6, 0xfd, 0xe0, 0xeb, 0xda, 0xd1, 0xcc, 0xc7, 0xae, 0xa5, 0xb8, 0xb3,
|
||||
0x82, 0x89, 0x94, 0x9f, 0x46, 0x4d, 0x50, 0x5b, 0x6a, 0x61, 0x7c, 0x77, 0x1e, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24,
|
||||
0x2f, 0x8d, 0x86, 0x9b, 0x90, 0xa1, 0xaa, 0xb7, 0xbc, 0xd5, 0xde, 0xc3, 0xc8, 0xf9, 0xf2, 0xef, 0xe4, 0x3d, 0x36,
|
||||
0x2b, 0x20, 0x11, 0x1a, 0x07, 0x0c, 0x65, 0x6e, 0x73, 0x78, 0x49, 0x42, 0x5f, 0x54, 0xf7, 0xfc, 0xe1, 0xea, 0xdb,
|
||||
0xd0, 0xcd, 0xc6, 0xaf, 0xa4, 0xb9, 0xb2, 0x83, 0x88, 0x95, 0x9e, 0x47, 0x4c, 0x51, 0x5a, 0x6b, 0x60, 0x7d, 0x76,
|
||||
0x1f, 0x14, 0x09, 0x02, 0x33, 0x38, 0x25, 0x2e, 0x8c, 0x87, 0x9a, 0x91, 0xa0, 0xab, 0xb6, 0xbd, 0xd4, 0xdf, 0xc2,
|
||||
0xc9, 0xf8, 0xf3, 0xee, 0xe5, 0x3c, 0x37, 0x2a, 0x21, 0x10, 0x1b, 0x06, 0x0d, 0x64, 0x6f, 0x72, 0x79, 0x48, 0x43,
|
||||
0x5e, 0x55, 0x01, 0x0a, 0x17, 0x1c, 0x2d, 0x26, 0x3b, 0x30, 0x59, 0x52, 0x4f, 0x44, 0x75, 0x7e, 0x63, 0x68, 0xb1,
|
||||
0xba, 0xa7, 0xac, 0x9d, 0x96, 0x8b, 0x80, 0xe9, 0xe2, 0xff, 0xf4, 0xc5, 0xce, 0xd3, 0xd8, 0x7a, 0x71, 0x6c, 0x67,
|
||||
0x56, 0x5d, 0x40, 0x4b, 0x22, 0x29, 0x34, 0x3f, 0x0e, 0x05, 0x18, 0x13, 0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0,
|
||||
0xfb, 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3
|
||||
};
|
||||
|
||||
static unsigned char xd[] = {
|
||||
0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b, 0xd0, 0xdd, 0xca,
|
||||
0xc7, 0xe4, 0xe9, 0xfe, 0xf3, 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b, 0xbb, 0xb6, 0xa1, 0xac, 0x8f, 0x82,
|
||||
0x95, 0x98, 0xd3, 0xde, 0xc9, 0xc4, 0xe7, 0xea, 0xfd, 0xf0, 0x6b, 0x66, 0x71, 0x7c, 0x5f, 0x52, 0x45, 0x48, 0x03,
|
||||
0x0e, 0x19, 0x14, 0x37, 0x3a, 0x2d, 0x20, 0x6d, 0x60, 0x77, 0x7a, 0x59, 0x54, 0x43, 0x4e, 0x05, 0x08, 0x1f, 0x12,
|
||||
0x31, 0x3c, 0x2b, 0x26, 0xbd, 0xb0, 0xa7, 0xaa, 0x89, 0x84, 0x93, 0x9e, 0xd5, 0xd8, 0xcf, 0xc2, 0xe1, 0xec, 0xfb,
|
||||
0xf6, 0xd6, 0xdb, 0xcc, 0xc1, 0xe2, 0xef, 0xf8, 0xf5, 0xbe, 0xb3, 0xa4, 0xa9, 0x8a, 0x87, 0x90, 0x9d, 0x06, 0x0b,
|
||||
0x1c, 0x11, 0x32, 0x3f, 0x28, 0x25, 0x6e, 0x63, 0x74, 0x79, 0x5a, 0x57, 0x40, 0x4d, 0xda, 0xd7, 0xc0, 0xcd, 0xee,
|
||||
0xe3, 0xf4, 0xf9, 0xb2, 0xbf, 0xa8, 0xa5, 0x86, 0x8b, 0x9c, 0x91, 0x0a, 0x07, 0x10, 0x1d, 0x3e, 0x33, 0x24, 0x29,
|
||||
0x62, 0x6f, 0x78, 0x75, 0x56, 0x5b, 0x4c, 0x41, 0x61, 0x6c, 0x7b, 0x76, 0x55, 0x58, 0x4f, 0x42, 0x09, 0x04, 0x13,
|
||||
0x1e, 0x3d, 0x30, 0x27, 0x2a, 0xb1, 0xbc, 0xab, 0xa6, 0x85, 0x88, 0x9f, 0x92, 0xd9, 0xd4, 0xc3, 0xce, 0xed, 0xe0,
|
||||
0xf7, 0xfa, 0xb7, 0xba, 0xad, 0xa0, 0x83, 0x8e, 0x99, 0x94, 0xdf, 0xd2, 0xc5, 0xc8, 0xeb, 0xe6, 0xf1, 0xfc, 0x67,
|
||||
0x6a, 0x7d, 0x70, 0x53, 0x5e, 0x49, 0x44, 0x0f, 0x02, 0x15, 0x18, 0x3b, 0x36, 0x21, 0x2c, 0x0c, 0x01, 0x16, 0x1b,
|
||||
0x38, 0x35, 0x22, 0x2f, 0x64, 0x69, 0x7e, 0x73, 0x50, 0x5d, 0x4a, 0x47, 0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2,
|
||||
0xff, 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97
|
||||
};
|
||||
|
||||
static unsigned char xe[] = {
|
||||
0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a, 0xe0, 0xee, 0xfc,
|
||||
0xf2, 0xd8, 0xd6, 0xc4, 0xca, 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba, 0xdb, 0xd5, 0xc7, 0xc9, 0xe3, 0xed,
|
||||
0xff, 0xf1, 0xab, 0xa5, 0xb7, 0xb9, 0x93, 0x9d, 0x8f, 0x81, 0x3b, 0x35, 0x27, 0x29, 0x03, 0x0d, 0x1f, 0x11, 0x4b,
|
||||
0x45, 0x57, 0x59, 0x73, 0x7d, 0x6f, 0x61, 0xad, 0xa3, 0xb1, 0xbf, 0x95, 0x9b, 0x89, 0x87, 0xdd, 0xd3, 0xc1, 0xcf,
|
||||
0xe5, 0xeb, 0xf9, 0xf7, 0x4d, 0x43, 0x51, 0x5f, 0x75, 0x7b, 0x69, 0x67, 0x3d, 0x33, 0x21, 0x2f, 0x05, 0x0b, 0x19,
|
||||
0x17, 0x76, 0x78, 0x6a, 0x64, 0x4e, 0x40, 0x52, 0x5c, 0x06, 0x08, 0x1a, 0x14, 0x3e, 0x30, 0x22, 0x2c, 0x96, 0x98,
|
||||
0x8a, 0x84, 0xae, 0xa0, 0xb2, 0xbc, 0xe6, 0xe8, 0xfa, 0xf4, 0xde, 0xd0, 0xc2, 0xcc, 0x41, 0x4f, 0x5d, 0x53, 0x79,
|
||||
0x77, 0x65, 0x6b, 0x31, 0x3f, 0x2d, 0x23, 0x09, 0x07, 0x15, 0x1b, 0xa1, 0xaf, 0xbd, 0xb3, 0x99, 0x97, 0x85, 0x8b,
|
||||
0xd1, 0xdf, 0xcd, 0xc3, 0xe9, 0xe7, 0xf5, 0xfb, 0x9a, 0x94, 0x86, 0x88, 0xa2, 0xac, 0xbe, 0xb0, 0xea, 0xe4, 0xf6,
|
||||
0xf8, 0xd2, 0xdc, 0xce, 0xc0, 0x7a, 0x74, 0x66, 0x68, 0x42, 0x4c, 0x5e, 0x50, 0x0a, 0x04, 0x16, 0x18, 0x32, 0x3c,
|
||||
0x2e, 0x20, 0xec, 0xe2, 0xf0, 0xfe, 0xd4, 0xda, 0xc8, 0xc6, 0x9c, 0x92, 0x80, 0x8e, 0xa4, 0xaa, 0xb8, 0xb6, 0x0c,
|
||||
0x02, 0x10, 0x1e, 0x34, 0x3a, 0x28, 0x26, 0x7c, 0x72, 0x60, 0x6e, 0x44, 0x4a, 0x58, 0x56, 0x37, 0x39, 0x2b, 0x25,
|
||||
0x0f, 0x01, 0x13, 0x1d, 0x47, 0x49, 0x5b, 0x55, 0x7f, 0x71, 0x63, 0x6d, 0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3,
|
||||
0xfd, 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d
|
||||
};
|
||||
|
||||
static unsigned int Rcon[] = { 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,
|
||||
0x20000000, 0x40000000, 0x80000000, 0x1b000000, 0x36000000 };
|
||||
|
||||
void Cipher(unsigned char cin[], unsigned int w[], int nr, unsigned char cout[])
|
||||
{
|
||||
unsigned int state[4], temp[4], in[4], out[4];
|
||||
unsigned int s00, s01, s02, s03, s10, s11, s12, s13;
|
||||
unsigned int s20, s21, s22, s23, s30, s31, s32, s33;
|
||||
int i;
|
||||
|
||||
in[0] = cin[0] << 24 | cin[1] << 16 | cin[2] << 8 | cin[3];
|
||||
in[1] = cin[4] << 24 | cin[5] << 16 | cin[6] << 8 | cin[7];
|
||||
in[2] = cin[8] << 24 | cin[9] << 16 | cin[10] << 8 | cin[11];
|
||||
in[3] = cin[12] << 24 | cin[13] << 16 | cin[14] << 8 | cin[15];
|
||||
#ifdef DEBUG
|
||||
printf("input: %.8x %.8x %.8x %.8x\n", in[0], in[1], in[2], in[3]);
|
||||
printf("k_sch: %.8x %.8x %.8x %.8x\n", w[0], w[1], w[2], w[3]);
|
||||
#endif
|
||||
state[0] = in[0] ^ w[0];
|
||||
state[1] = in[1] ^ w[1];
|
||||
state[2] = in[2] ^ w[2];
|
||||
state[3] = in[3] ^ w[3];
|
||||
|
||||
for (i = 4; i < 4 * nr; i += 4)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("start: %.8x %.8x %.8x %.8x\n", state[0], state[1], state[2], state[3]);
|
||||
#endif
|
||||
state[0] = SubBytes(state[0]);
|
||||
state[1] = SubBytes(state[1]);
|
||||
state[2] = SubBytes(state[2]);
|
||||
state[3] = SubBytes(state[3]);
|
||||
#ifdef DEBUG
|
||||
printf("s_box: %.8x %.8x %.8x %.8x\n", state[0], state[1], state[2], state[3]);
|
||||
#endif
|
||||
temp[0] = (state[0] & 0xff000000) | (state[1] & 0xff0000) | (state[2] & 0xff00) | (state[3] & 0xff);
|
||||
temp[1] = (state[1] & 0xff000000) | (state[2] & 0xff0000) | (state[3] & 0xff00) | (state[0] & 0xff);
|
||||
temp[2] = (state[2] & 0xff000000) | (state[3] & 0xff0000) | (state[0] & 0xff00) | (state[1] & 0xff);
|
||||
temp[3] = (state[3] & 0xff000000) | (state[0] & 0xff0000) | (state[1] & 0xff00) | (state[2] & 0xff);
|
||||
#ifdef DEBUG
|
||||
printf("s_row: %.8x %.8x %.8x %.8x\n", temp[0], temp[1], temp[2], temp[3]);
|
||||
#endif
|
||||
s00 = temp[0] >> 24 & 0xff;
|
||||
s10 = temp[0] >> 16 & 0xff;
|
||||
s20 = temp[0] >> 8 & 0xff;
|
||||
s30 = temp[0] & 0xff;
|
||||
s01 = temp[1] >> 24 & 0xff;
|
||||
s11 = temp[1] >> 16 & 0xff;
|
||||
s21 = temp[1] >> 8 & 0xff;
|
||||
s31 = temp[1] & 0xff;
|
||||
s02 = temp[2] >> 24 & 0xff;
|
||||
s12 = temp[2] >> 16 & 0xff;
|
||||
s22 = temp[2] >> 8 & 0xff;
|
||||
s32 = temp[2] & 0xff;
|
||||
s03 = temp[3] >> 24 & 0xff;
|
||||
s13 = temp[3] >> 16 & 0xff;
|
||||
s23 = temp[3] >> 8 & 0xff;
|
||||
s33 = temp[3] & 0xff;
|
||||
state[0] = (x2[s00] ^ x3[s10] ^ s20 ^ s30) << 24 | (s00 ^ x2[s10] ^ x3[s20] ^ s30) << 16 |
|
||||
(s00 ^ s10 ^ x2[s20] ^ x3[s30]) << 8 | (x3[s00] ^ s10 ^ s20 ^ x2[s30]);
|
||||
state[1] = (x2[s01] ^ x3[s11] ^ s21 ^ s31) << 24 | (s01 ^ x2[s11] ^ x3[s21] ^ s31) << 16 |
|
||||
(s01 ^ s11 ^ x2[s21] ^ x3[s31]) << 8 | (x3[s01] ^ s11 ^ s21 ^ x2[s31]);
|
||||
state[2] = (x2[s02] ^ x3[s12] ^ s22 ^ s32) << 24 | (s02 ^ x2[s12] ^ x3[s22] ^ s32) << 16 |
|
||||
(s02 ^ s12 ^ x2[s22] ^ x3[s32]) << 8 | (x3[s02] ^ s12 ^ s22 ^ x2[s32]);
|
||||
state[3] = (x2[s03] ^ x3[s13] ^ s23 ^ s33) << 24 | (s03 ^ x2[s13] ^ x3[s23] ^ s33) << 16 |
|
||||
(s03 ^ s13 ^ x2[s23] ^ x3[s33]) << 8 | (x3[s03] ^ s13 ^ s23 ^ x2[s33]);
|
||||
#ifdef DEBUG
|
||||
printf("m_col: %.8x %.8x %.8x %.8x\n", state[0], state[1], state[2], state[3]);
|
||||
printf("k_sch: %.8x %.8x %.8x %.8x\n", w[i], w[i + 1], w[i + 2], w[i + 3]);
|
||||
#endif
|
||||
state[0] ^= w[i];
|
||||
state[1] ^= w[i + 1];
|
||||
state[2] ^= w[i + 2];
|
||||
state[3] ^= w[i + 3];
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("start: %.8x %.8x %.8x %.8x\n", state[0], state[1], state[2], state[3]);
|
||||
#endif
|
||||
state[0] = SubBytes(state[0]);
|
||||
state[1] = SubBytes(state[1]);
|
||||
state[2] = SubBytes(state[2]);
|
||||
state[3] = SubBytes(state[3]);
|
||||
#ifdef DEBUG
|
||||
printf("s_box: %.8x %.8x %.8x %.8x\n", state[0], state[1], state[2], state[3]);
|
||||
#endif
|
||||
temp[0] = (state[0] & 0xff000000) | (state[1] & 0xff0000) | (state[2] & 0xff00) | (state[3] & 0xff);
|
||||
temp[1] = (state[1] & 0xff000000) | (state[2] & 0xff0000) | (state[3] & 0xff00) | (state[0] & 0xff);
|
||||
temp[2] = (state[2] & 0xff000000) | (state[3] & 0xff0000) | (state[0] & 0xff00) | (state[1] & 0xff);
|
||||
temp[3] = (state[3] & 0xff000000) | (state[0] & 0xff0000) | (state[1] & 0xff00) | (state[2] & 0xff);
|
||||
#ifdef DEBUG
|
||||
printf("s_row: %.8x %.8x %.8x %.8x\n", temp[0], temp[1], temp[2], temp[3]);
|
||||
printf("k_sch: %.8x %.8x %.8x %.8x\n", w[4 * nr], w[4 * nr + 1], w[4 * nr + 2], w[4 * nr + 3]);
|
||||
#endif
|
||||
out[0] = temp[0] ^ w[4 * nr];
|
||||
out[1] = temp[1] ^ w[4 * nr + 1];
|
||||
out[2] = temp[2] ^ w[4 * nr + 2];
|
||||
out[3] = temp[3] ^ w[4 * nr + 3];
|
||||
#ifdef DEBUG
|
||||
printf("output: %.8x %.8x %.8x %.8x\n", out[0], out[1], out[2], out[3]);
|
||||
#endif
|
||||
cout[0] = out[0] >> 24 & 0xff;
|
||||
cout[1] = out[0] >> 16 & 0xff;
|
||||
cout[2] = out[0] >> 8 & 0xff;
|
||||
cout[3] = out[0] & 0xff;
|
||||
cout[4] = out[1] >> 24 & 0xff;
|
||||
cout[5] = out[1] >> 16 & 0xff;
|
||||
cout[6] = out[1] >> 8 & 0xff;
|
||||
cout[7] = out[1] & 0xff;
|
||||
cout[8] = out[2] >> 24 & 0xff;
|
||||
cout[9] = out[2] >> 16 & 0xff;
|
||||
cout[10] = out[2] >> 8 & 0xff;
|
||||
cout[11] = out[2] & 0xff;
|
||||
cout[12] = out[3] >> 24 & 0xff;
|
||||
cout[13] = out[3] >> 16 & 0xff;
|
||||
cout[14] = out[3] >> 8 & 0xff;
|
||||
cout[15] = out[3] & 0xff;
|
||||
}
|
||||
|
||||
void InvCipher(unsigned char cin[], unsigned int w[], int nr, unsigned char cout[])
|
||||
{
|
||||
unsigned int state[4], temp[4], in[4], out[4];
|
||||
unsigned int s00, s01, s02, s03, s10, s11, s12, s13;
|
||||
unsigned int s20, s21, s22, s23, s30, s31, s32, s33;
|
||||
int i;
|
||||
|
||||
in[0] = cin[0] << 24 | cin[1] << 16 | cin[2] << 8 | cin[3];
|
||||
in[1] = cin[4] << 24 | cin[5] << 16 | cin[6] << 8 | cin[7];
|
||||
in[2] = cin[8] << 24 | cin[9] << 16 | cin[10] << 8 | cin[11];
|
||||
in[3] = cin[12] << 24 | cin[13] << 16 | cin[14] << 8 | cin[15];
|
||||
#ifdef DEBUG
|
||||
printf("iinput: %.8x %.8x %.8x %.8x\n", in[0], in[1], in[2], in[3]);
|
||||
printf("ik_sch: %.8x %.8x %.8x %.8x\n", w[4 * nr], w[4 * nr + 1], w[4 * nr + 2], w[4 * nr + 3]);
|
||||
#endif
|
||||
state[0] = in[0] ^ w[4 * nr];
|
||||
state[1] = in[1] ^ w[4 * nr + 1];
|
||||
state[2] = in[2] ^ w[4 * nr + 2];
|
||||
state[3] = in[3] ^ w[4 * nr + 3];
|
||||
|
||||
for (i = 4 * nr - 4; i > 0; i -= 4)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf("istart: %.8x %.8x %.8x %.8x\n", state[0], state[1], state[2], state[3]);
|
||||
#endif
|
||||
temp[0] = (state[0] & 0xff000000) | (state[3] & 0xff0000) | (state[2] & 0xff00) | (state[1] & 0xff);
|
||||
temp[1] = (state[1] & 0xff000000) | (state[0] & 0xff0000) | (state[3] & 0xff00) | (state[2] & 0xff);
|
||||
temp[2] = (state[2] & 0xff000000) | (state[1] & 0xff0000) | (state[0] & 0xff00) | (state[3] & 0xff);
|
||||
temp[3] = (state[3] & 0xff000000) | (state[2] & 0xff0000) | (state[1] & 0xff00) | (state[0] & 0xff);
|
||||
#ifdef DEBUG
|
||||
printf("is_row: %.8x %.8x %.8x %.8x\n", temp[0], temp[1], temp[2], temp[3]);
|
||||
#endif
|
||||
state[0] = InvSubBytes(temp[0]);
|
||||
state[1] = InvSubBytes(temp[1]);
|
||||
state[2] = InvSubBytes(temp[2]);
|
||||
state[3] = InvSubBytes(temp[3]);
|
||||
#ifdef DEBUG
|
||||
printf("is_box: %.8x %.8x %.8x %.8x\n", state[0], state[1], state[2], state[3]);
|
||||
printf("ik_sch: %.8x %.8x %.8x %.8x\n", w[i], w[i + 1], w[i + 2], w[i + 3]);
|
||||
#endif
|
||||
state[0] ^= w[i];
|
||||
state[1] ^= w[i + 1];
|
||||
state[2] ^= w[i + 2];
|
||||
state[3] ^= w[i + 3];
|
||||
#ifdef DEBUG
|
||||
printf("ik_add: %.8x %.8x %.8x %.8x\n", state[0], state[1], state[2], state[3]);
|
||||
#endif
|
||||
s00 = state[0] >> 24 & 0xff;
|
||||
s10 = state[0] >> 16 & 0xff;
|
||||
s20 = state[0] >> 8 & 0xff;
|
||||
s30 = state[0] & 0xff;
|
||||
s01 = state[1] >> 24 & 0xff;
|
||||
s11 = state[1] >> 16 & 0xff;
|
||||
s21 = state[1] >> 8 & 0xff;
|
||||
s31 = state[1] & 0xff;
|
||||
s02 = state[2] >> 24 & 0xff;
|
||||
s12 = state[2] >> 16 & 0xff;
|
||||
s22 = state[2] >> 8 & 0xff;
|
||||
s32 = state[2] & 0xff;
|
||||
s03 = state[3] >> 24 & 0xff;
|
||||
s13 = state[3] >> 16 & 0xff;
|
||||
s23 = state[3] >> 8 & 0xff;
|
||||
s33 = state[3] & 0xff;
|
||||
state[0] = (xe[s00] ^ xb[s10] ^ xd[s20] ^ x9[s30]) << 24 | (x9[s00] ^ xe[s10] ^ xb[s20] ^ xd[s30]) << 16 |
|
||||
(xd[s00] ^ x9[s10] ^ xe[s20] ^ xb[s30]) << 8 | (xb[s00] ^ xd[s10] ^ x9[s20] ^ xe[s30]);
|
||||
state[1] = (xe[s01] ^ xb[s11] ^ xd[s21] ^ x9[s31]) << 24 | (x9[s01] ^ xe[s11] ^ xb[s21] ^ xd[s31]) << 16 |
|
||||
(xd[s01] ^ x9[s11] ^ xe[s21] ^ xb[s31]) << 8 | (xb[s01] ^ xd[s11] ^ x9[s21] ^ xe[s31]);
|
||||
state[2] = (xe[s02] ^ xb[s12] ^ xd[s22] ^ x9[s32]) << 24 | (x9[s02] ^ xe[s12] ^ xb[s22] ^ xd[s32]) << 16 |
|
||||
(xd[s02] ^ x9[s12] ^ xe[s22] ^ xb[s32]) << 8 | (xb[s02] ^ xd[s12] ^ x9[s22] ^ xe[s32]);
|
||||
state[3] = (xe[s03] ^ xb[s13] ^ xd[s23] ^ x9[s33]) << 24 | (x9[s03] ^ xe[s13] ^ xb[s23] ^ xd[s33]) << 16 |
|
||||
(xd[s03] ^ x9[s13] ^ xe[s23] ^ xb[s33]) << 8 | (xb[s03] ^ xd[s13] ^ x9[s23] ^ xe[s33]);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("istart: %.8x %.8x %.8x %.8x\n", state[0], state[1], state[2], state[3]);
|
||||
#endif
|
||||
temp[0] = (state[0] & 0xff000000) | (state[3] & 0xff0000) | (state[2] & 0xff00) | (state[1] & 0xff);
|
||||
temp[1] = (state[1] & 0xff000000) | (state[0] & 0xff0000) | (state[3] & 0xff00) | (state[2] & 0xff);
|
||||
temp[2] = (state[2] & 0xff000000) | (state[1] & 0xff0000) | (state[0] & 0xff00) | (state[3] & 0xff);
|
||||
temp[3] = (state[3] & 0xff000000) | (state[2] & 0xff0000) | (state[1] & 0xff00) | (state[0] & 0xff);
|
||||
#ifdef DEBUG
|
||||
printf("is_row: %.8x %.8x %.8x %.8x\n", temp[0], temp[1], temp[2], temp[3]);
|
||||
#endif
|
||||
state[0] = InvSubBytes(temp[0]);
|
||||
state[1] = InvSubBytes(temp[1]);
|
||||
state[2] = InvSubBytes(temp[2]);
|
||||
state[3] = InvSubBytes(temp[3]);
|
||||
#ifdef DEBUG
|
||||
printf("is_box: %.8x %.8x %.8x %.8x\n", state[0], state[1], state[2], state[3]);
|
||||
printf("ik_sch: %.8x %.8x %.8x %.8x\n", w[0], w[1], w[2], w[3]);
|
||||
#endif
|
||||
out[0] = state[0] ^ w[0];
|
||||
out[1] = state[1] ^ w[1];
|
||||
out[2] = state[2] ^ w[2];
|
||||
out[3] = state[3] ^ w[3];
|
||||
#ifdef DEBUG
|
||||
printf("ioutput: %.8x %.8x %.8x %.8x\n", out[0], out[1], out[2], out[3]);
|
||||
#endif
|
||||
cout[0] = out[0] >> 24 & 0xff;
|
||||
cout[1] = out[0] >> 16 & 0xff;
|
||||
cout[2] = out[0] >> 8 & 0xff;
|
||||
cout[3] = out[0] & 0xff;
|
||||
cout[4] = out[1] >> 24 & 0xff;
|
||||
cout[5] = out[1] >> 16 & 0xff;
|
||||
cout[6] = out[1] >> 8 & 0xff;
|
||||
cout[7] = out[1] & 0xff;
|
||||
cout[8] = out[2] >> 24 & 0xff;
|
||||
cout[9] = out[2] >> 16 & 0xff;
|
||||
cout[10] = out[2] >> 8 & 0xff;
|
||||
cout[11] = out[2] & 0xff;
|
||||
cout[12] = out[3] >> 24 & 0xff;
|
||||
cout[13] = out[3] >> 16 & 0xff;
|
||||
cout[14] = out[3] >> 8 & 0xff;
|
||||
cout[15] = out[3] & 0xff;
|
||||
}
|
||||
|
||||
void KeyExpansion(unsigned char ckey[], int nbits, unsigned int w[])
|
||||
{
|
||||
int i, j;
|
||||
unsigned int temp, tempx;
|
||||
|
||||
j = nbits / 32;
|
||||
for (i = 0; i < j; i++)
|
||||
w[i] = ckey[4 * i] << 24 | ckey[4 * i + 1] << 16 | ckey[4 * i + 2] << 8 | ckey[4 * i + 3];
|
||||
|
||||
for (i = j; i < 4 * j + 28; i++)
|
||||
{
|
||||
temp = w[i - 1];
|
||||
if ((i % j) == 0)
|
||||
{
|
||||
tempx = temp << 8 | (temp >> 24 & 0xff);
|
||||
temp = SubBytes(tempx) ^ Rcon[i / j - 1];
|
||||
}
|
||||
else if (j == 8 && (i % j) == 4)
|
||||
temp = SubBytes(temp);
|
||||
w[i] = w[i - j] ^ temp;
|
||||
}
|
||||
}
|
||||
269
apps/elftosb/common/crc.cpp
Normal file
269
apps/elftosb/common/crc.cpp
Normal file
@@ -0,0 +1,269 @@
|
||||
/*
|
||||
* File: crc.cpp
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
|
||||
#include "crc.h"
|
||||
|
||||
//! Table of CRC-32's of all single byte values. The values in
|
||||
//! this table are those used in the Ethernet CRC algorithm.
|
||||
const uint32_t CRC32::m_tab[] = {
|
||||
//#ifdef __LITTLE_ENDIAN__
|
||||
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005, 0x2608edb8,
|
||||
0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
|
||||
0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f, 0x639b0da6,
|
||||
0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
|
||||
0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84,
|
||||
0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
|
||||
0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a,
|
||||
0xec7dd02d, 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
|
||||
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07,
|
||||
0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
|
||||
0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, 0xaca5c697, 0xa864db20, 0xa527fdf9,
|
||||
0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
|
||||
0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 0xf3b06b3b,
|
||||
0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
|
||||
0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c,
|
||||
0x774bb0eb, 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
|
||||
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b, 0x0315d626,
|
||||
0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
|
||||
0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8,
|
||||
0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
|
||||
0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, 0x8832161a,
|
||||
0x8cf30bad, 0x81b02d74, 0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
|
||||
0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, 0x61043093,
|
||||
0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
|
||||
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679,
|
||||
0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
|
||||
0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09, 0x8d79e0be, 0x803ac667,
|
||||
0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
|
||||
0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
|
||||
//#else
|
||||
// 0x00000000,
|
||||
// 0xb71dc104, 0x6e3b8209, 0xd926430d, 0xdc760413, 0x6b6bc517,
|
||||
// 0xb24d861a, 0x0550471e, 0xb8ed0826, 0x0ff0c922, 0xd6d68a2f,
|
||||
// 0x61cb4b2b, 0x649b0c35, 0xd386cd31, 0x0aa08e3c, 0xbdbd4f38,
|
||||
// 0x70db114c, 0xc7c6d048, 0x1ee09345, 0xa9fd5241, 0xacad155f,
|
||||
// 0x1bb0d45b, 0xc2969756, 0x758b5652, 0xc836196a, 0x7f2bd86e,
|
||||
// 0xa60d9b63, 0x11105a67, 0x14401d79, 0xa35ddc7d, 0x7a7b9f70,
|
||||
// 0xcd665e74, 0xe0b62398, 0x57abe29c, 0x8e8da191, 0x39906095,
|
||||
// 0x3cc0278b, 0x8bdde68f, 0x52fba582, 0xe5e66486, 0x585b2bbe,
|
||||
// 0xef46eaba, 0x3660a9b7, 0x817d68b3, 0x842d2fad, 0x3330eea9,
|
||||
// 0xea16ada4, 0x5d0b6ca0, 0x906d32d4, 0x2770f3d0, 0xfe56b0dd,
|
||||
// 0x494b71d9, 0x4c1b36c7, 0xfb06f7c3, 0x2220b4ce, 0x953d75ca,
|
||||
// 0x28803af2, 0x9f9dfbf6, 0x46bbb8fb, 0xf1a679ff, 0xf4f63ee1,
|
||||
// 0x43ebffe5, 0x9acdbce8, 0x2dd07dec, 0x77708634, 0xc06d4730,
|
||||
// 0x194b043d, 0xae56c539, 0xab068227, 0x1c1b4323, 0xc53d002e,
|
||||
// 0x7220c12a, 0xcf9d8e12, 0x78804f16, 0xa1a60c1b, 0x16bbcd1f,
|
||||
// 0x13eb8a01, 0xa4f64b05, 0x7dd00808, 0xcacdc90c, 0x07ab9778,
|
||||
// 0xb0b6567c, 0x69901571, 0xde8dd475, 0xdbdd936b, 0x6cc0526f,
|
||||
// 0xb5e61162, 0x02fbd066, 0xbf469f5e, 0x085b5e5a, 0xd17d1d57,
|
||||
// 0x6660dc53, 0x63309b4d, 0xd42d5a49, 0x0d0b1944, 0xba16d840,
|
||||
// 0x97c6a5ac, 0x20db64a8, 0xf9fd27a5, 0x4ee0e6a1, 0x4bb0a1bf,
|
||||
// 0xfcad60bb, 0x258b23b6, 0x9296e2b2, 0x2f2bad8a, 0x98366c8e,
|
||||
// 0x41102f83, 0xf60dee87, 0xf35da999, 0x4440689d, 0x9d662b90,
|
||||
// 0x2a7bea94, 0xe71db4e0, 0x500075e4, 0x892636e9, 0x3e3bf7ed,
|
||||
// 0x3b6bb0f3, 0x8c7671f7, 0x555032fa, 0xe24df3fe, 0x5ff0bcc6,
|
||||
// 0xe8ed7dc2, 0x31cb3ecf, 0x86d6ffcb, 0x8386b8d5, 0x349b79d1,
|
||||
// 0xedbd3adc, 0x5aa0fbd8, 0xeee00c69, 0x59fdcd6d, 0x80db8e60,
|
||||
// 0x37c64f64, 0x3296087a, 0x858bc97e, 0x5cad8a73, 0xebb04b77,
|
||||
// 0x560d044f, 0xe110c54b, 0x38368646, 0x8f2b4742, 0x8a7b005c,
|
||||
// 0x3d66c158, 0xe4408255, 0x535d4351, 0x9e3b1d25, 0x2926dc21,
|
||||
// 0xf0009f2c, 0x471d5e28, 0x424d1936, 0xf550d832, 0x2c769b3f,
|
||||
// 0x9b6b5a3b, 0x26d61503, 0x91cbd407, 0x48ed970a, 0xfff0560e,
|
||||
// 0xfaa01110, 0x4dbdd014, 0x949b9319, 0x2386521d, 0x0e562ff1,
|
||||
// 0xb94beef5, 0x606dadf8, 0xd7706cfc, 0xd2202be2, 0x653deae6,
|
||||
// 0xbc1ba9eb, 0x0b0668ef, 0xb6bb27d7, 0x01a6e6d3, 0xd880a5de,
|
||||
// 0x6f9d64da, 0x6acd23c4, 0xddd0e2c0, 0x04f6a1cd, 0xb3eb60c9,
|
||||
// 0x7e8d3ebd, 0xc990ffb9, 0x10b6bcb4, 0xa7ab7db0, 0xa2fb3aae,
|
||||
// 0x15e6fbaa, 0xccc0b8a7, 0x7bdd79a3, 0xc660369b, 0x717df79f,
|
||||
// 0xa85bb492, 0x1f467596, 0x1a163288, 0xad0bf38c, 0x742db081,
|
||||
// 0xc3307185, 0x99908a5d, 0x2e8d4b59, 0xf7ab0854, 0x40b6c950,
|
||||
// 0x45e68e4e, 0xf2fb4f4a, 0x2bdd0c47, 0x9cc0cd43, 0x217d827b,
|
||||
// 0x9660437f, 0x4f460072, 0xf85bc176, 0xfd0b8668, 0x4a16476c,
|
||||
// 0x93300461, 0x242dc565, 0xe94b9b11, 0x5e565a15, 0x87701918,
|
||||
// 0x306dd81c, 0x353d9f02, 0x82205e06, 0x5b061d0b, 0xec1bdc0f,
|
||||
// 0x51a69337, 0xe6bb5233, 0x3f9d113e, 0x8880d03a, 0x8dd09724,
|
||||
// 0x3acd5620, 0xe3eb152d, 0x54f6d429, 0x7926a9c5, 0xce3b68c1,
|
||||
// 0x171d2bcc, 0xa000eac8, 0xa550add6, 0x124d6cd2, 0xcb6b2fdf,
|
||||
// 0x7c76eedb, 0xc1cba1e3, 0x76d660e7, 0xaff023ea, 0x18ede2ee,
|
||||
// 0x1dbda5f0, 0xaaa064f4, 0x738627f9, 0xc49be6fd, 0x09fdb889,
|
||||
// 0xbee0798d, 0x67c63a80, 0xd0dbfb84, 0xd58bbc9a, 0x62967d9e,
|
||||
// 0xbbb03e93, 0x0cadff97, 0xb110b0af, 0x060d71ab, 0xdf2b32a6,
|
||||
// 0x6836f3a2, 0x6d66b4bc, 0xda7b75b8, 0x035d36b5, 0xb440f7b1
|
||||
//#endif // __LITTLE_ENDIAN__
|
||||
|
||||
// This is the original table that came with this source.
|
||||
//#ifdef __LITTLE_ENDIAN__
|
||||
// 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
|
||||
// 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
|
||||
// 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
|
||||
// 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
|
||||
// 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
|
||||
// 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
|
||||
// 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
|
||||
// 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
|
||||
// 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
|
||||
// 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
|
||||
// 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
|
||||
// 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
|
||||
// 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
|
||||
// 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
|
||||
// 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
|
||||
// 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
|
||||
// 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
|
||||
// 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
|
||||
// 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
|
||||
// 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
|
||||
// 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
|
||||
// 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
|
||||
// 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
|
||||
// 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
|
||||
// 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
|
||||
// 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
|
||||
// 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
|
||||
// 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
|
||||
// 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
|
||||
// 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
|
||||
// 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
|
||||
// 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
|
||||
// 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
|
||||
// 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
|
||||
// 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
|
||||
// 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
|
||||
// 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
|
||||
// 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
|
||||
// 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
|
||||
// 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
|
||||
// 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
|
||||
// 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
|
||||
// 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
|
||||
// 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
|
||||
// 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
|
||||
// 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
|
||||
// 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
|
||||
// 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
|
||||
// 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
|
||||
// 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
|
||||
// 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
|
||||
// 0x2d02ef8dL
|
||||
//#else
|
||||
// 0x00000000L, 0x96300777L, 0x2c610eeeL, 0xba510999L, 0x19c46d07L,
|
||||
// 0x8ff46a70L, 0x35a563e9L, 0xa395649eL, 0x3288db0eL, 0xa4b8dc79L,
|
||||
// 0x1ee9d5e0L, 0x88d9d297L, 0x2b4cb609L, 0xbd7cb17eL, 0x072db8e7L,
|
||||
// 0x911dbf90L, 0x6410b71dL, 0xf220b06aL, 0x4871b9f3L, 0xde41be84L,
|
||||
// 0x7dd4da1aL, 0xebe4dd6dL, 0x51b5d4f4L, 0xc785d383L, 0x56986c13L,
|
||||
// 0xc0a86b64L, 0x7af962fdL, 0xecc9658aL, 0x4f5c0114L, 0xd96c0663L,
|
||||
// 0x633d0ffaL, 0xf50d088dL, 0xc8206e3bL, 0x5e10694cL, 0xe44160d5L,
|
||||
// 0x727167a2L, 0xd1e4033cL, 0x47d4044bL, 0xfd850dd2L, 0x6bb50aa5L,
|
||||
// 0xfaa8b535L, 0x6c98b242L, 0xd6c9bbdbL, 0x40f9bcacL, 0xe36cd832L,
|
||||
// 0x755cdf45L, 0xcf0dd6dcL, 0x593dd1abL, 0xac30d926L, 0x3a00de51L,
|
||||
// 0x8051d7c8L, 0x1661d0bfL, 0xb5f4b421L, 0x23c4b356L, 0x9995bacfL,
|
||||
// 0x0fa5bdb8L, 0x9eb80228L, 0x0888055fL, 0xb2d90cc6L, 0x24e90bb1L,
|
||||
// 0x877c6f2fL, 0x114c6858L, 0xab1d61c1L, 0x3d2d66b6L, 0x9041dc76L,
|
||||
// 0x0671db01L, 0xbc20d298L, 0x2a10d5efL, 0x8985b171L, 0x1fb5b606L,
|
||||
// 0xa5e4bf9fL, 0x33d4b8e8L, 0xa2c90778L, 0x34f9000fL, 0x8ea80996L,
|
||||
// 0x18980ee1L, 0xbb0d6a7fL, 0x2d3d6d08L, 0x976c6491L, 0x015c63e6L,
|
||||
// 0xf4516b6bL, 0x62616c1cL, 0xd8306585L, 0x4e0062f2L, 0xed95066cL,
|
||||
// 0x7ba5011bL, 0xc1f40882L, 0x57c40ff5L, 0xc6d9b065L, 0x50e9b712L,
|
||||
// 0xeab8be8bL, 0x7c88b9fcL, 0xdf1ddd62L, 0x492dda15L, 0xf37cd38cL,
|
||||
// 0x654cd4fbL, 0x5861b24dL, 0xce51b53aL, 0x7400bca3L, 0xe230bbd4L,
|
||||
// 0x41a5df4aL, 0xd795d83dL, 0x6dc4d1a4L, 0xfbf4d6d3L, 0x6ae96943L,
|
||||
// 0xfcd96e34L, 0x468867adL, 0xd0b860daL, 0x732d0444L, 0xe51d0333L,
|
||||
// 0x5f4c0aaaL, 0xc97c0dddL, 0x3c710550L, 0xaa410227L, 0x10100bbeL,
|
||||
// 0x86200cc9L, 0x25b56857L, 0xb3856f20L, 0x09d466b9L, 0x9fe461ceL,
|
||||
// 0x0ef9de5eL, 0x98c9d929L, 0x2298d0b0L, 0xb4a8d7c7L, 0x173db359L,
|
||||
// 0x810db42eL, 0x3b5cbdb7L, 0xad6cbac0L, 0x2083b8edL, 0xb6b3bf9aL,
|
||||
// 0x0ce2b603L, 0x9ad2b174L, 0x3947d5eaL, 0xaf77d29dL, 0x1526db04L,
|
||||
// 0x8316dc73L, 0x120b63e3L, 0x843b6494L, 0x3e6a6d0dL, 0xa85a6a7aL,
|
||||
// 0x0bcf0ee4L, 0x9dff0993L, 0x27ae000aL, 0xb19e077dL, 0x44930ff0L,
|
||||
// 0xd2a30887L, 0x68f2011eL, 0xfec20669L, 0x5d5762f7L, 0xcb676580L,
|
||||
// 0x71366c19L, 0xe7066b6eL, 0x761bd4feL, 0xe02bd389L, 0x5a7ada10L,
|
||||
// 0xcc4add67L, 0x6fdfb9f9L, 0xf9efbe8eL, 0x43beb717L, 0xd58eb060L,
|
||||
// 0xe8a3d6d6L, 0x7e93d1a1L, 0xc4c2d838L, 0x52f2df4fL, 0xf167bbd1L,
|
||||
// 0x6757bca6L, 0xdd06b53fL, 0x4b36b248L, 0xda2b0dd8L, 0x4c1b0aafL,
|
||||
// 0xf64a0336L, 0x607a0441L, 0xc3ef60dfL, 0x55df67a8L, 0xef8e6e31L,
|
||||
// 0x79be6946L, 0x8cb361cbL, 0x1a8366bcL, 0xa0d26f25L, 0x36e26852L,
|
||||
// 0x95770cccL, 0x03470bbbL, 0xb9160222L, 0x2f260555L, 0xbe3bbac5L,
|
||||
// 0x280bbdb2L, 0x925ab42bL, 0x046ab35cL, 0xa7ffd7c2L, 0x31cfd0b5L,
|
||||
// 0x8b9ed92cL, 0x1daede5bL, 0xb0c2649bL, 0x26f263ecL, 0x9ca36a75L,
|
||||
// 0x0a936d02L, 0xa906099cL, 0x3f360eebL, 0x85670772L, 0x13570005L,
|
||||
// 0x824abf95L, 0x147ab8e2L, 0xae2bb17bL, 0x381bb60cL, 0x9b8ed292L,
|
||||
// 0x0dbed5e5L, 0xb7efdc7cL, 0x21dfdb0bL, 0xd4d2d386L, 0x42e2d4f1L,
|
||||
// 0xf8b3dd68L, 0x6e83da1fL, 0xcd16be81L, 0x5b26b9f6L, 0xe177b06fL,
|
||||
// 0x7747b718L, 0xe65a0888L, 0x706a0fffL, 0xca3b0666L, 0x5c0b0111L,
|
||||
// 0xff9e658fL, 0x69ae62f8L, 0xd3ff6b61L, 0x45cf6c16L, 0x78e20aa0L,
|
||||
// 0xeed20dd7L, 0x5483044eL, 0xc2b30339L, 0x612667a7L, 0xf71660d0L,
|
||||
// 0x4d476949L, 0xdb776e3eL, 0x4a6ad1aeL, 0xdc5ad6d9L, 0x660bdf40L,
|
||||
// 0xf03bd837L, 0x53aebca9L, 0xc59ebbdeL, 0x7fcfb247L, 0xe9ffb530L,
|
||||
// 0x1cf2bdbdL, 0x8ac2bacaL, 0x3093b353L, 0xa6a3b424L, 0x0536d0baL,
|
||||
// 0x9306d7cdL, 0x2957de54L, 0xbf67d923L, 0x2e7a66b3L, 0xb84a61c4L,
|
||||
// 0x021b685dL, 0x942b6f2aL, 0x37be0bb4L, 0xa18e0cc3L, 0x1bdf055aL,
|
||||
// 0x8def022dL
|
||||
//#endif
|
||||
};
|
||||
|
||||
CRC32::CRC32()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
void CRC32::update(const uint8_t *s, unsigned n)
|
||||
{
|
||||
uint32_t crc = m_crc;
|
||||
m_count += n;
|
||||
|
||||
while (n--)
|
||||
{
|
||||
uint8_t c = *s++ & 0xff;
|
||||
crc = (crc << 8) ^ m_tab[(crc >> 24) ^ c];
|
||||
}
|
||||
|
||||
// for(; !((reinterpret_cast<uint32_t>(s) & 0x3) == 0) && n > 0; n--)
|
||||
// {
|
||||
// crc = m_tab[CRC32_INDEX(crc) ^ *s++] ^ CRC32_SHIFTED(crc);
|
||||
// }
|
||||
//
|
||||
// while (n >= 4)
|
||||
// {
|
||||
// crc ^= *(const uint32_t *)s;
|
||||
// crc = m_tab[CRC32_INDEX(crc)] ^ CRC32_SHIFTED(crc);
|
||||
// crc = m_tab[CRC32_INDEX(crc)] ^ CRC32_SHIFTED(crc);
|
||||
// crc = m_tab[CRC32_INDEX(crc)] ^ CRC32_SHIFTED(crc);
|
||||
// crc = m_tab[CRC32_INDEX(crc)] ^ CRC32_SHIFTED(crc);
|
||||
// n -= 4;
|
||||
// s += 4;
|
||||
// }
|
||||
//
|
||||
// while (n--)
|
||||
// {
|
||||
// crc = m_tab[CRC32_INDEX(crc) ^ *s++] ^ CRC32_SHIFTED(crc);
|
||||
// }
|
||||
|
||||
m_crc = crc;
|
||||
}
|
||||
|
||||
void CRC32::truncatedFinal(uint8_t *hash, unsigned size)
|
||||
{
|
||||
// pad with zeroes
|
||||
if (m_count % 4)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = m_count % 4; i < 4; i++)
|
||||
{
|
||||
m_crc = (m_crc << 8) ^ m_tab[(m_crc >> 24) ^ 0];
|
||||
}
|
||||
}
|
||||
|
||||
// m_crc ^= CRC32_NEGL;
|
||||
|
||||
unsigned i;
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
hash[i] = getCrcByte(i);
|
||||
}
|
||||
|
||||
reset();
|
||||
}
|
||||
51
apps/elftosb/common/crc.h
Normal file
51
apps/elftosb/common/crc.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* File: crc.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
#if !defined(_crc_h_)
|
||||
#define CRYPTOPP_CRC32_H
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
const uint32_t CRC32_NEGL = 0xffffffffL;
|
||||
|
||||
#ifdef __LITTLE_ENDIAN__
|
||||
#define CRC32_INDEX(c) (c & 0xff)
|
||||
#define CRC32_SHIFTED(c) (c >> 8)
|
||||
#else
|
||||
#define CRC32_INDEX(c) (c >> 24)
|
||||
#define CRC32_SHIFTED(c) (c << 8)
|
||||
#endif
|
||||
|
||||
//! CRC Checksum Calculation
|
||||
class CRC32
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
DIGESTSIZE = 4
|
||||
};
|
||||
|
||||
CRC32();
|
||||
|
||||
void update(const uint8_t *input, unsigned length);
|
||||
|
||||
void truncatedFinal(uint8_t *hash, unsigned size);
|
||||
|
||||
void updateByte(uint8_t b) { m_crc = m_tab[CRC32_INDEX(m_crc) ^ b] ^ CRC32_SHIFTED(m_crc); }
|
||||
uint8_t getCrcByte(unsigned i) const { return ((uint8_t *)&(m_crc))[i]; }
|
||||
private:
|
||||
void reset()
|
||||
{
|
||||
m_crc = CRC32_NEGL;
|
||||
m_count = 0;
|
||||
}
|
||||
|
||||
static const uint32_t m_tab[256];
|
||||
uint32_t m_crc;
|
||||
unsigned m_count;
|
||||
};
|
||||
|
||||
#endif // _crc_h_
|
||||
78
apps/elftosb/common/format_string.cpp
Normal file
78
apps/elftosb/common/format_string.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* File: format_string.cpp
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
|
||||
#include "format_string.h"
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdexcept>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
//! Size of the temporary buffer to hold the formatted output string.
|
||||
#define WIN32_FMT_BUF_LEN (512)
|
||||
|
||||
/*!
|
||||
* \brief Simple template class to free a pointer.
|
||||
*/
|
||||
template <typename T>
|
||||
class free_ptr
|
||||
{
|
||||
public:
|
||||
//! \brief Constructor.
|
||||
free_ptr(T ptr)
|
||||
: m_p(ptr)
|
||||
{
|
||||
}
|
||||
|
||||
//! \brief Destructor.
|
||||
~free_ptr()
|
||||
{
|
||||
if (m_p)
|
||||
{
|
||||
free(m_p);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
T m_p; //!< The value to free.
|
||||
};
|
||||
|
||||
//! The purpose of this function to provide a convenient way of generating formatted
|
||||
//! STL strings inline. This is especially useful when throwing exceptions that take
|
||||
//! a std::string for a message. The length of the formatted output string is limited
|
||||
//! only by memory. Memory temporarily allocated for the output string is disposed of
|
||||
//! before returning.
|
||||
//!
|
||||
//! Example usage:
|
||||
//! \code
|
||||
//! throw std::runtime_error(format_string("error on line %d", line));
|
||||
//! \endcode
|
||||
//!
|
||||
//! \param fmt Format string using printf-style format markers.
|
||||
//! \return An STL string object of the formatted output.
|
||||
std::string format_string(const char *fmt, ...)
|
||||
{
|
||||
char *buf = 0;
|
||||
va_list vargs;
|
||||
va_start(vargs, fmt);
|
||||
int result = -1;
|
||||
#if WIN32
|
||||
buf = (char *)malloc(WIN32_FMT_BUF_LEN);
|
||||
if (buf)
|
||||
{
|
||||
result = _vsnprintf(buf, WIN32_FMT_BUF_LEN, fmt, vargs);
|
||||
}
|
||||
#else // WIN32
|
||||
result = vasprintf(&buf, fmt, vargs);
|
||||
#endif // WIN32
|
||||
va_end(vargs);
|
||||
if (result != -1 && buf)
|
||||
{
|
||||
free_ptr<char *> freebuf(buf);
|
||||
return std::string(buf);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
18
apps/elftosb/common/format_string.h
Normal file
18
apps/elftosb/common/format_string.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* File: format_string.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
#if !defined(_format_string_h_)
|
||||
#define _format_string_h_
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
/*!
|
||||
* \brief Returns a formatted STL string using printf format strings.
|
||||
*/
|
||||
std::string format_string(const char *fmt, ...);
|
||||
|
||||
#endif // _format_string_h_
|
||||
22
apps/elftosb/common/int_size.h
Normal file
22
apps/elftosb/common/int_size.h
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* File: int_size.h
|
||||
*
|
||||
* Copyright (c) Freescale Semiconductor, Inc. All rights reserved.
|
||||
* See included license file for license details.
|
||||
*/
|
||||
#if !defined(_int_size_h_)
|
||||
#define _int_size_h_
|
||||
|
||||
namespace elftosb
|
||||
{
|
||||
//! Supported sizes of integers.
|
||||
typedef enum
|
||||
{
|
||||
kWordSize, //!< 32-bit word.
|
||||
kHalfWordSize, //!< 16-bit half word.
|
||||
kByteSize //!< 8-bit byte.
|
||||
} int_size_t;
|
||||
|
||||
}; // namespace elftosb
|
||||
|
||||
#endif // _int_size_h_
|
||||
1263
apps/elftosb/common/options.cpp
Normal file
1263
apps/elftosb/common/options.cpp
Normal file
File diff suppressed because it is too large
Load Diff
456
apps/elftosb/common/options.h
Normal file
456
apps/elftosb/common/options.h
Normal file
@@ -0,0 +1,456 @@
|
||||
// ****************************************************************************
|
||||
// ^FILE: options.h - option parsing classes
|
||||
//
|
||||
// ^DESCRIPTION:
|
||||
// This file defines classes used to parse command-line options.
|
||||
// Options may be parsed from an array of strings, or from any structure
|
||||
// for which a corresponding option-iterator exists.
|
||||
//
|
||||
// ^HISTORY:
|
||||
// 03/06/92 Brad Appleton <bradapp@enteract.com> Created
|
||||
//
|
||||
// 03/23/93 Brad Appleton <bradapp@enteract.com>
|
||||
// - Added OptIstreamIter class
|
||||
//
|
||||
// 03/08/94 Brad Appleton <bradapp@enteract.com>
|
||||
// - Added Options::reset() member function
|
||||
//
|
||||
// 07/31/97 Brad Appleton <bradapp@enteract.com>
|
||||
// - Added PARSE_POS control flag and POSITIONAL return value
|
||||
//
|
||||
// 04/30/06 Chris Reed
|
||||
// - Updated to modern C++ and STL
|
||||
// - Converted comments to doxygen style
|
||||
// ^^**************************************************************************
|
||||
|
||||
#ifndef _options_h
|
||||
#define _options_h
|
||||
|
||||
#ifdef USE_STDIO
|
||||
#include <stdio.h>
|
||||
#else
|
||||
#include <iostream>
|
||||
#endif
|
||||
|
||||
//! Abstract class to iterate through options/arguments
|
||||
//!
|
||||
class OptIter
|
||||
{
|
||||
public:
|
||||
OptIter(void) {}
|
||||
virtual ~OptIter(void);
|
||||
|
||||
//! curr() returns the current item in the iterator without
|
||||
//! advancing on to the next item. If we are at the end of items
|
||||
//! then NULL is returned.
|
||||
virtual const char *curr(void) = 0;
|
||||
|
||||
//! next() advances to the next item.
|
||||
virtual void next(void) = 0;
|
||||
|
||||
//! operator() returns the current item in the iterator and then
|
||||
//! advances on to the next item. If we are at the end of items
|
||||
//! then NULL is returned.
|
||||
virtual const char *operator()(void);
|
||||
};
|
||||
|
||||
//! Abstract class for a rewindable OptIter
|
||||
//!
|
||||
class OptIterRwd : public OptIter
|
||||
{
|
||||
public:
|
||||
OptIterRwd(void);
|
||||
|
||||
virtual ~OptIterRwd(void);
|
||||
|
||||
virtual const char *curr(void) = 0;
|
||||
|
||||
virtual void next(void) = 0;
|
||||
|
||||
virtual const char *operator()(void) = 0;
|
||||
|
||||
//! rewind() resets the "current-element" to the first one in the "list"
|
||||
virtual void rewind(void) = 0;
|
||||
};
|
||||
|
||||
//! Class to iterate through an array of tokens. The array may be terminated
|
||||
//! by NULL or a count containing the number of tokens may be given.
|
||||
//!
|
||||
class OptArgvIter : public OptIterRwd
|
||||
{
|
||||
private:
|
||||
int ndx; // index of current arg
|
||||
int ac; // arg count
|
||||
const char *const *av; // arg vector
|
||||
|
||||
public:
|
||||
OptArgvIter(const char *const argv[])
|
||||
: av(argv)
|
||||
, ac(-1)
|
||||
, ndx(0)
|
||||
{
|
||||
}
|
||||
|
||||
OptArgvIter(int argc, const char *const argv[])
|
||||
: av(argv)
|
||||
, ac(argc)
|
||||
, ndx(0)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~OptArgvIter(void);
|
||||
|
||||
virtual const char *curr(void);
|
||||
|
||||
virtual void next(void);
|
||||
|
||||
virtual const char *operator()(void);
|
||||
|
||||
virtual void rewind(void);
|
||||
|
||||
//! index returns the current index to use for argv[]
|
||||
int index(void) { return ndx; }
|
||||
};
|
||||
|
||||
//! Class to iterate through a string containing delimiter-separated tokens
|
||||
//!
|
||||
class OptStrTokIter : public OptIterRwd
|
||||
{
|
||||
private:
|
||||
unsigned len; // length of token-string
|
||||
const char *str; // the token-string
|
||||
const char *seps; // delimiter-set (separator-characters)
|
||||
const char *cur; // current token
|
||||
char *tokstr; // our copy of the token-string
|
||||
|
||||
static const char *default_delims; // default delimiters = whitespace
|
||||
|
||||
public:
|
||||
OptStrTokIter(const char *tokens, const char *delimiters = 0);
|
||||
|
||||
virtual ~OptStrTokIter(void);
|
||||
|
||||
virtual const char *curr(void);
|
||||
|
||||
virtual void next(void);
|
||||
|
||||
virtual const char *operator()(void);
|
||||
|
||||
virtual void rewind(void);
|
||||
|
||||
//! delimiters() with NO arguments returns the current set of delimiters,
|
||||
//! If an argument is given then it is used as the new set of delimiters.
|
||||
const char *delimiters(void) { return seps; }
|
||||
void delimiters(const char *delims) { seps = (delims) ? delims : default_delims; }
|
||||
};
|
||||
|
||||
//! OptIstreamIter is a class for iterating over arguments that come
|
||||
//! from an input stream. Each line of the input stream is considered
|
||||
//! to be a set of white-space separated tokens. If the the first
|
||||
//! non-white character on a line is '#' ('!' for VMS systems) then
|
||||
//! the line is considered a comment and is ignored.
|
||||
//!
|
||||
//! \note If a line is more than 1022 characters in length then we
|
||||
//! treat it as if it were several lines of length 1022 or less.
|
||||
//!
|
||||
//! \note The string tokens returned by this iterator are pointers
|
||||
//! to temporary buffers which may not necessarily stick around
|
||||
//! for too long after the call to curr() or operator(), hence
|
||||
//! if you need the string value to persist - you will need to
|
||||
//! make a copy.
|
||||
//!
|
||||
class OptIstreamIter : public OptIter
|
||||
{
|
||||
private:
|
||||
std::istream &is;
|
||||
OptStrTokIter *tok_iter;
|
||||
|
||||
void fill(void);
|
||||
|
||||
public:
|
||||
static const unsigned MAX_LINE_LEN;
|
||||
|
||||
OptIstreamIter(std::istream &input);
|
||||
|
||||
virtual ~OptIstreamIter(void);
|
||||
|
||||
virtual const char *curr(void);
|
||||
|
||||
virtual void next(void);
|
||||
|
||||
virtual const char *operator()(void);
|
||||
};
|
||||
|
||||
//! \brief parse command-line options
|
||||
//!
|
||||
//! \section Synopsis
|
||||
//! \code
|
||||
//! #include <options.h>
|
||||
//!
|
||||
//! Options opts(cmdname, optv);
|
||||
//! char cmdname[], *optv[];
|
||||
//! \endcode
|
||||
//! \section Description
|
||||
//! The Options constructor expects a command-name (usually argv[0]) and
|
||||
//! a pointer to an array of strings. The last element in this array MUST
|
||||
//! be NULL. Each non-NULL string in the array must have the following format:
|
||||
//!
|
||||
//! The 1st character must be the option-name ('c' for a -c option).
|
||||
//!
|
||||
//! The 2nd character must be one of '|', '?', ':', '*', or '+'.
|
||||
//! '|' -- indicates that the option takes NO argument;
|
||||
//! '?' -- indicates that the option takes an OPTIONAL argument;
|
||||
//! ':' -- indicates that the option takes a REQUIRED argument;
|
||||
//! '*' -- indicates that the option takes 0 or more arguments;
|
||||
//! '+' -- indicates that the option takes 1 or more arguments;
|
||||
//!
|
||||
//! The remainder of the string must be the long-option name.
|
||||
//!
|
||||
//! If desired, the long-option name may be followed by one or more
|
||||
//! spaces and then by the name of the option value. This name will
|
||||
//! be used when printing usage messages. If the option-value-name
|
||||
//! is not given then the string "<value>" will be used in usage
|
||||
//! messages.
|
||||
//!
|
||||
//! One may use a space to indicate that a particular option does not
|
||||
//! have a corresponding long-option. For example, "c: " (or "c:")
|
||||
//! means the -c option takes a value & has NO corresponding long-option.
|
||||
//!
|
||||
//! To specify a long-option that has no corresponding single-character
|
||||
//! option is a bit trickier: Options::operator() still needs an "option-
|
||||
//! character" to return when that option is matched. One may use a whitespace
|
||||
//! character or a non-printable character as the single-character option
|
||||
//! in such a case. (hence " |hello" would only match "--hello").
|
||||
//!
|
||||
//! \section Exceptions Exceptions to the above
|
||||
//! If the 1st character of the string is '-', then the rest of the
|
||||
//! string must correspond to the above format, and the option is
|
||||
//! considered to be a hidden-option. This means it will be parsed
|
||||
//! when actually matching options from the command-line, but will
|
||||
//! NOT show-up if a usage message is printed using the usage() member
|
||||
//! function. Such an example might be "-h|hidden". If you want to
|
||||
//! use any "dummy" options (options that are not parsed, but that
|
||||
//! to show up in the usage message), you can specify them along with
|
||||
//! any positional parameters to the usage() member function.
|
||||
//!
|
||||
//! If the 2nd character of the string is '\0' then it is assumed
|
||||
//! that there is no corresponding long-option and that the option
|
||||
//! takes no argument (hence "f", and "f| " are equivalent).
|
||||
//!
|
||||
//! \code
|
||||
//! const char * optv[] = {
|
||||
//! "c:count <number>",
|
||||
//! "s?str <string>",
|
||||
//! "x",
|
||||
//! " |hello",
|
||||
//! "g+groups <newsgroup>",
|
||||
//! NULL
|
||||
//! } ;
|
||||
//! \endcode
|
||||
//! optv[] now corresponds to the following:
|
||||
//!
|
||||
//! usage: cmdname [-c|--count <number>] [-s|--str [<string>]]
|
||||
//! [-x] [--hello] [-g|--groups <newsgroup> ...]
|
||||
//!
|
||||
//! Long-option names are matched case-insensitive and only a unique prefix
|
||||
//! of the name needs to be specified.
|
||||
//!
|
||||
//! Option-name characters are case-sensitive!
|
||||
//!
|
||||
//! \section Caveat
|
||||
//! Because of the way in which multi-valued options and options with optional
|
||||
//! values are handled, it is NOT possible to supply a value to an option in
|
||||
//! a separate argument (different argv[] element) if the value is OPTIONAL
|
||||
//! and begins with a '-'. What this means is that if an option "-s" takes an
|
||||
//! optional value value and you wish to supply a value of "-foo" then you must
|
||||
//! specify this on the command-line as "-s-foo" instead of "-s -foo" because
|
||||
//! "-s -foo" will be considered to be two separate sets of options.
|
||||
//!
|
||||
//! A multi-valued option is terminated by another option or by the end-of
|
||||
//! options. The following are all equivalent (if "-l" is a multi-valued
|
||||
//! option and "-x" is an option that takes no value):
|
||||
//!
|
||||
//! cmdname -x -l item1 item2 item3 -- arg1 arg2 arg3
|
||||
//! cmdname -x -litem1 -litem2 -litem3 -- arg1 arg2 arg3
|
||||
//! cmdname -l item1 item2 item3 -x arg1 arg2 arg3
|
||||
//!
|
||||
//!
|
||||
//! \code
|
||||
//! #include <options.h>
|
||||
//!
|
||||
//! static const char * optv[] = {
|
||||
//! "H|help",
|
||||
//! "c:count <number>",
|
||||
//! "s?str <string>",
|
||||
//! "x",
|
||||
//! " |hello",
|
||||
//! "g+groups <newsgroup>",
|
||||
//! NULL
|
||||
//! } ;
|
||||
//!
|
||||
//! main(int argc, char * argv[]) {
|
||||
//! int optchar;
|
||||
//! const char * optarg;
|
||||
//! const char * str = "default_string";
|
||||
//! int count = 0, xflag = 0, hello = 0;
|
||||
//! int errors = 0, ngroups = 0;
|
||||
//!
|
||||
//! Options opts(*argv, optv);
|
||||
//! OptArgvIter iter(--argc, ++argv);
|
||||
//!
|
||||
//! while( optchar = opts(iter, optarg) ) {
|
||||
//! switch (optchar) {
|
||||
//! case 'H' :
|
||||
//! opts.usage(cout, "files ...");
|
||||
//! exit(0);
|
||||
//! break;
|
||||
//! case 'g' :
|
||||
//! ++ngroups; break; //! the groupname is in "optarg"
|
||||
//! case 's' :
|
||||
//! str = optarg; break;
|
||||
//! case 'x' :
|
||||
//! ++xflag; break;
|
||||
//! case ' ' :
|
||||
//! ++hello; break;
|
||||
//! case 'c' :
|
||||
//! if (optarg == NULL) ++errors;
|
||||
//! else count = (int) atol(optarg);
|
||||
//! break;
|
||||
//! default : ++errors; break;
|
||||
//! } //!switch
|
||||
//! }
|
||||
//!
|
||||
//! if (errors || (iter.index() == argc)) {
|
||||
//! if (! errors) {
|
||||
//! cerr << opts.name() << ": no filenames given." << endl ;
|
||||
//! }
|
||||
//! opts.usage(cerr, "files ...");
|
||||
//! exit(1);
|
||||
//! }
|
||||
//!
|
||||
//! cout << "xflag=" << ((xflag) ? "ON" : "OFF") << endl
|
||||
//! << "hello=" << ((hello) ? "YES" : "NO") << endl
|
||||
//! << "count=" << count << endl
|
||||
//! << "str=\"" << ((str) ? str : "No value given!") << "\"" << endl
|
||||
//! << "ngroups=" << ngroups << endl ;
|
||||
//!
|
||||
//! if (iter.index() < argc) {
|
||||
//! cout << "files=" ;
|
||||
//! for (int i = iter.index() ; i < argc ; i++) {
|
||||
//! cout << "\"" << argv[i] << "\" " ;
|
||||
//! }
|
||||
//! cout << endl ;
|
||||
//! }
|
||||
//! }
|
||||
//! \endcode
|
||||
class Options
|
||||
{
|
||||
private:
|
||||
unsigned explicit_end : 1; //!< were we terminated because of "--"?
|
||||
unsigned optctrls : 7; //!< control settings (a set of OptCtrl masks)
|
||||
const char *const *optvec; //!< vector of option-specifications (last=NULL)
|
||||
const char *nextchar; //!< next option-character to process
|
||||
const char *listopt; //!< last list-option we matched
|
||||
const char *cmdname; //!< name of the command
|
||||
|
||||
void check_syntax(void) const;
|
||||
|
||||
const char *match_opt(char opt, int ignore_case = 0) const;
|
||||
|
||||
const char *match_longopt(const char *opt, int len, int &ambiguous) const;
|
||||
|
||||
int parse_opt(OptIter &iter, const char *&optarg);
|
||||
|
||||
int parse_longopt(OptIter &iter, const char *&optarg);
|
||||
|
||||
public:
|
||||
enum OptCtrl
|
||||
{
|
||||
DEFAULT = 0x00, //!< Default setting
|
||||
ANYCASE = 0x01, //!< Ignore case when matching short-options
|
||||
QUIET = 0x02, //!< Dont print error messages
|
||||
PLUS = 0x04, //!< Allow "+" as a long-option prefix
|
||||
SHORT_ONLY = 0x08, //!< Dont accept long-options
|
||||
LONG_ONLY = 0x10, //!< Dont accept short-options
|
||||
//!< (also allows "-" as a long-option prefix).
|
||||
NOGUESSING = 0x20, //!< Normally, when we see a short (long) option
|
||||
//!< on the command line that doesnt match any
|
||||
//!< known short (long) options, then we try to
|
||||
//!< "guess" by seeing if it will match any known
|
||||
//!< long (short) option. Setting this mask prevents
|
||||
//!< this "guessing" from occurring.
|
||||
PARSE_POS = 0x40 //!< By default, Options will not present positional
|
||||
//!< command-line arguments to the user and will
|
||||
//!< instead stop parsing when the first positonal
|
||||
//!< argument has been encountered. If this flag
|
||||
//!< is given, Options will present positional
|
||||
//!< arguments to the user with a return code of
|
||||
//!< POSITIONAL; ENDOPTS will be returned only
|
||||
//!< when the end of the argument list is reached.
|
||||
};
|
||||
|
||||
//! Error return values for operator()
|
||||
//!
|
||||
enum OptRC
|
||||
{
|
||||
ENDOPTS = 0,
|
||||
BADCHAR = -1,
|
||||
BADKWD = -2,
|
||||
AMBIGUOUS = -3,
|
||||
POSITIONAL = -4
|
||||
};
|
||||
|
||||
Options(const char *name, const char *const optv[]);
|
||||
|
||||
virtual ~Options(void);
|
||||
|
||||
//! name() returns the command name
|
||||
const char *name(void) const { return cmdname; }
|
||||
//! ctrls() (with no arguments) returns the existing control settings
|
||||
unsigned ctrls(void) const { return optctrls; }
|
||||
//! ctrls() (with 1 argument) sets new control settings
|
||||
void ctrls(unsigned newctrls) { optctrls = newctrls; }
|
||||
//! reset for another pass to parse for options
|
||||
void reset(void) { nextchar = listopt = NULL; }
|
||||
//! usage() prints options usage (followed by any positional arguments
|
||||
//! listed in the parameter "positionals") on the given outstream
|
||||
void usage(std::ostream &os, const char *positionals) const;
|
||||
|
||||
//! operator() iterates through the arguments as necessary (using the
|
||||
//! given iterator) and returns the character value of the option
|
||||
//! (or long-option) that it matched. If the option has a value
|
||||
//! then the value given may be found in optarg (otherwise optarg
|
||||
//! will be NULL).
|
||||
//!
|
||||
//! 0 is returned upon end-of-options. At this point, "iter" may
|
||||
//! be used to process any remaining positional parameters. If the
|
||||
//! PARSE_POS control-flag is set then 0 is returned only when all
|
||||
//! arguments in "iter" have been exhausted.
|
||||
//!
|
||||
//! If an invalid option is found then BADCHAR is returned and *optarg
|
||||
//! is the unrecognized option character.
|
||||
//!
|
||||
//! If an invalid long-option is found then BADKWD is returned and optarg
|
||||
//! points to the bad long-option.
|
||||
//!
|
||||
//! If an ambiguous long-option is found then AMBIGUOUS is returned and
|
||||
//! optarg points to the ambiguous long-option.
|
||||
//!
|
||||
//! If the PARSE_POS control-flag is set then POSITIONAL is returned
|
||||
//! when a positional argument is encountered and optarg points to
|
||||
//! the positonal argument (and "iter" is advanced to the next argument
|
||||
//! in the iterator).
|
||||
//!
|
||||
//! Unless Options::QUIET is used, missing option-arguments and
|
||||
//! invalid options (and the like) will automatically cause error
|
||||
//! messages to be issued to cerr.
|
||||
int operator()(OptIter &iter, const char *&optarg);
|
||||
|
||||
//! Call this member function after operator() has returned 0
|
||||
//! if you want to know whether or not options were explicitly
|
||||
//! terminated because "--" appeared on the command-line.
|
||||
//!
|
||||
int explicit_endopts() const { return explicit_end; }
|
||||
};
|
||||
|
||||
#endif /* _options_h */
|
||||
1410
apps/elftosb/common/rijndael.cpp
Normal file
1410
apps/elftosb/common/rijndael.cpp
Normal file
File diff suppressed because it is too large
Load Diff
180
apps/elftosb/common/rijndael.h
Normal file
180
apps/elftosb/common/rijndael.h
Normal file
@@ -0,0 +1,180 @@
|
||||
#ifndef _RIJNDAEL_H_
|
||||
#define _RIJNDAEL_H_
|
||||
|
||||
//
|
||||
// File : rijndael.h
|
||||
// Creation date : Sun Nov 5 2000 03:21:05 CEST
|
||||
// Author : Szymon Stefanek (stefanek@tin.it)
|
||||
//
|
||||
// Another implementation of the Rijndael cipher.
|
||||
// This is intended to be an easily usable library file.
|
||||
// This code is public domain.
|
||||
// Based on the Vincent Rijmen and K.U.Leuven implementation 2.4.
|
||||
//
|
||||
|
||||
//
|
||||
// Original Copyright notice:
|
||||
//
|
||||
// rijndael-alg-fst.c v2.4 April '2000
|
||||
// rijndael-alg-fst.h
|
||||
// rijndael-api-fst.c
|
||||
// rijndael-api-fst.h
|
||||
//
|
||||
// Optimised ANSI C code
|
||||
//
|
||||
// authors: v1.0: Antoon Bosselaers
|
||||
// v2.0: Vincent Rijmen, K.U.Leuven
|
||||
// v2.3: Paulo Barreto
|
||||
// v2.4: Vincent Rijmen, K.U.Leuven
|
||||
//
|
||||
// This code is placed in the public domain.
|
||||
//
|
||||
|
||||
//
|
||||
// This implementation works on 128 , 192 , 256 bit keys
|
||||
// and on 128 bit blocks
|
||||
//
|
||||
|
||||
//
|
||||
// Example of usage:
|
||||
//
|
||||
// // Input data
|
||||
// unsigned char key[32]; // The key
|
||||
// initializeYour256BitKey(); // Obviously initialized with sth
|
||||
// const unsigned char * plainText = getYourPlainText(); // Your plain text
|
||||
// int plainTextLen = strlen(plainText); // Plain text length
|
||||
//
|
||||
// // Encrypting
|
||||
// Rijndael rin;
|
||||
// unsigned char output[plainTextLen + 16];
|
||||
//
|
||||
// rin.init(Rijndael::CBC,Rijndael::Encrypt,key,Rijndael::Key32Bytes);
|
||||
// // It is a good idea to check the error code
|
||||
// int len = rin.padEncrypt(plainText,len,output);
|
||||
// if(len >= 0)useYourEncryptedText();
|
||||
// else encryptError(len);
|
||||
//
|
||||
// // Decrypting: we can reuse the same object
|
||||
// unsigned char output2[len];
|
||||
// rin.init(Rijndael::CBC,Rijndael::Decrypt,key,Rijndael::Key32Bytes));
|
||||
// len = rin.padDecrypt(output,len,output2);
|
||||
// if(len >= 0)useYourDecryptedText();
|
||||
// else decryptError(len);
|
||||
//
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#define _MAX_KEY_COLUMNS (256 / 32)
|
||||
#define _MAX_ROUNDS 14
|
||||
#define MAX_IV_SIZE 16
|
||||
|
||||
// We assume that unsigned int is 32 bits long....
|
||||
// typedef unsigned char uint8_t;
|
||||
// typedef unsigned int uint32_t;
|
||||
// typedef unsigned short uint16_t;
|
||||
|
||||
// Error codes
|
||||
#define RIJNDAEL_SUCCESS 0
|
||||
#define RIJNDAEL_UNSUPPORTED_MODE -1
|
||||
#define RIJNDAEL_UNSUPPORTED_DIRECTION -2
|
||||
#define RIJNDAEL_UNSUPPORTED_KEY_LENGTH -3
|
||||
#define RIJNDAEL_BAD_KEY -4
|
||||
#define RIJNDAEL_NOT_INITIALIZED -5
|
||||
#define RIJNDAEL_BAD_DIRECTION -6
|
||||
#define RIJNDAEL_CORRUPTED_DATA -7
|
||||
|
||||
class Rijndael
|
||||
{
|
||||
public:
|
||||
enum Direction
|
||||
{
|
||||
Encrypt,
|
||||
Decrypt
|
||||
};
|
||||
enum Mode
|
||||
{
|
||||
ECB,
|
||||
CBC,
|
||||
CFB1
|
||||
};
|
||||
enum KeyLength
|
||||
{
|
||||
Key16Bytes,
|
||||
Key24Bytes,
|
||||
Key32Bytes
|
||||
};
|
||||
//
|
||||
// Creates a Rijndael cipher object
|
||||
// You have to call init() before you can encrypt or decrypt stuff
|
||||
//
|
||||
Rijndael();
|
||||
~Rijndael();
|
||||
|
||||
protected:
|
||||
// Internal stuff
|
||||
enum State
|
||||
{
|
||||
Valid,
|
||||
Invalid
|
||||
};
|
||||
|
||||
State m_state;
|
||||
Mode m_mode;
|
||||
Direction m_direction;
|
||||
uint8_t m_initVector[MAX_IV_SIZE];
|
||||
uint32_t m_uRounds;
|
||||
uint8_t m_expandedKey[_MAX_ROUNDS + 1][4][4];
|
||||
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// API
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// init(): Initializes the crypt session
|
||||
// Returns RIJNDAEL_SUCCESS or an error code
|
||||
// mode : Rijndael::ECB, Rijndael::CBC or Rijndael::CFB1
|
||||
// You have to use the same mode for encrypting and decrypting
|
||||
// dir : Rijndael::Encrypt or Rijndael::Decrypt
|
||||
// A cipher instance works only in one direction
|
||||
// (Well , it could be easily modified to work in both
|
||||
// directions with a single init() call, but it looks
|
||||
// useless to me...anyway , it is a matter of generating
|
||||
// two expanded keys)
|
||||
// key : array of unsigned octets , it can be 16 , 24 or 32 bytes long
|
||||
// this CAN be binary data (it is not expected to be null terminated)
|
||||
// keyLen : Rijndael::Key16Bytes , Rijndael::Key24Bytes or Rijndael::Key32Bytes
|
||||
// initVector: initialization vector, you will usually use 0 here
|
||||
int init(Mode mode, Direction dir, const uint8_t *key, KeyLength keyLen, uint8_t *initVector = 0);
|
||||
// Encrypts the input array (can be binary data)
|
||||
// The input array length must be a multiple of 16 bytes, the remaining part
|
||||
// is DISCARDED.
|
||||
// so it actually encrypts inputLen / 128 blocks of input and puts it in outBuffer
|
||||
// Input len is in BITS!
|
||||
// outBuffer must be at least inputLen / 8 bytes long.
|
||||
// Returns the encrypted buffer length in BITS or an error code < 0 in case of error
|
||||
int blockEncrypt(const uint8_t *input, int inputLen, uint8_t *outBuffer);
|
||||
// Encrypts the input array (can be binary data)
|
||||
// The input array can be any length , it is automatically padded on a 16 byte boundary.
|
||||
// Input len is in BYTES!
|
||||
// outBuffer must be at least (inputLen + 16) bytes long
|
||||
// Returns the encrypted buffer length in BYTES or an error code < 0 in case of error
|
||||
int padEncrypt(const uint8_t *input, int inputOctets, uint8_t *outBuffer);
|
||||
// Decrypts the input vector
|
||||
// Input len is in BITS!
|
||||
// outBuffer must be at least inputLen / 8 bytes long
|
||||
// Returns the decrypted buffer length in BITS and an error code < 0 in case of error
|
||||
int blockDecrypt(const uint8_t *input, int inputLen, uint8_t *outBuffer);
|
||||
// Decrypts the input vector
|
||||
// Input len is in BYTES!
|
||||
// outBuffer must be at least inputLen bytes long
|
||||
// Returns the decrypted buffer length in BYTES and an error code < 0 in case of error
|
||||
int padDecrypt(const uint8_t *input, int inputOctets, uint8_t *outBuffer);
|
||||
|
||||
protected:
|
||||
void keySched(uint8_t key[_MAX_KEY_COLUMNS][4]);
|
||||
void keyEncToDec();
|
||||
void encrypt(const uint8_t a[16], uint8_t b[16]);
|
||||
void decrypt(const uint8_t a[16], uint8_t b[16]);
|
||||
};
|
||||
|
||||
#endif // _RIJNDAEL_H_
|
||||
218
apps/elftosb/common/smart_ptr.h
Normal file
218
apps/elftosb/common/smart_ptr.h
Normal file
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* smart_ptr.h
|
||||
* elftosb
|
||||
*
|
||||
* Created by Chris Reed on 4/18/06.
|
||||
* Copyright 2006 __MyCompanyName__. All rights reserved.
|
||||
*
|
||||
*/
|
||||
#if !defined(_smart_ptr_h_)
|
||||
#define _smart_ptr_h_
|
||||
|
||||
/*!
|
||||
* \brief Simple, standard smart pointer class.
|
||||
*
|
||||
* This class only supports the single-owner paradigm.
|
||||
*/
|
||||
template <typename T>
|
||||
class smart_ptr
|
||||
{
|
||||
public:
|
||||
typedef T data_type;
|
||||
typedef T *ptr_type;
|
||||
typedef const T *const_ptr_type;
|
||||
typedef T &ref_type;
|
||||
typedef const T &const_ref_type;
|
||||
|
||||
//! Default constuctor. Initialises with no pointer set.
|
||||
smart_ptr()
|
||||
: _p(0)
|
||||
{
|
||||
}
|
||||
|
||||
//! This constructor takes a pointer to the object to be deleted.
|
||||
smart_ptr(ptr_type p)
|
||||
: _p(p)
|
||||
{
|
||||
}
|
||||
|
||||
//! Destructor. If an object (pointer) has been set, it will be deleted.
|
||||
//! Deletes the object using safe_delete().
|
||||
virtual ~smart_ptr() { safe_delete(); }
|
||||
//! Return the current pointer value.
|
||||
ptr_type get() { return _p; }
|
||||
//! Return the const form of the current pointer value.
|
||||
const_ptr_type get() const { return _p; }
|
||||
//! Change the pointer value, or set if if the default constructor was used.
|
||||
//! If a pointer had previously been associated with the object, and \a p is
|
||||
//! different than that previous pointer, it will be deleted before taking
|
||||
//! ownership of \a p. If this is not desired, call reset() beforehand.
|
||||
void set(ptr_type p)
|
||||
{
|
||||
if (_p && p != _p)
|
||||
{
|
||||
safe_delete();
|
||||
}
|
||||
_p = p;
|
||||
}
|
||||
|
||||
//! Dissociates any previously set pointer value without deleting it.
|
||||
void reset() { _p = 0; }
|
||||
//! Dissociates a previously set pointer value, deleting it at the same time.
|
||||
void clear() { safe_delete(); }
|
||||
//! Forces immediate deletion of the object. If you are planning on using
|
||||
//! this method, think about just using a normal pointer. It probably makes
|
||||
//! more sense.
|
||||
virtual void safe_delete()
|
||||
{
|
||||
if (_p)
|
||||
{
|
||||
delete _p;
|
||||
_p = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//! \name Operators
|
||||
//@{
|
||||
|
||||
//! Makes the object transparent as the template type.
|
||||
operator ptr_type() { return _p; }
|
||||
//! Const version of the pointer operator.
|
||||
operator const_ptr_type() const { return _p; }
|
||||
//! Makes the object transparent as a reference of the template type.
|
||||
operator ref_type() { return *_p; }
|
||||
//! Const version of the reference operator.
|
||||
operator const_ref_type() const { return *_p; }
|
||||
//! Returns a boolean indicating whether the object has a pointer set or not.
|
||||
operator bool() const { return _p != 0; }
|
||||
//! To allow setting the pointer directly. Equivalent to a call to set().
|
||||
smart_ptr<T> &operator=(const_ptr_type p)
|
||||
{
|
||||
set(const_cast<ptr_type>(p));
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Another operator to allow you to treat the object just like a pointer.
|
||||
ptr_type operator->() { return _p; }
|
||||
//! Another operator to allow you to treat the object just like a pointer.
|
||||
const_ptr_type operator->() const { return _p; }
|
||||
// //! Pointer dereferencing operator.
|
||||
// ref_type operator * () const { return *_p; }
|
||||
//
|
||||
// //! Const version of the pointer dereference operator.
|
||||
// const_ref_type operator * () const { return *_p; }
|
||||
|
||||
//@}
|
||||
|
||||
protected:
|
||||
ptr_type _p; //!< The wrapped pointer.
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Simple, standard smart pointer class that uses the array delete operator.
|
||||
*
|
||||
* This class only supports the single-owner paradigm.
|
||||
*
|
||||
* This is almost entirely a copy of smart_ptr since the final C++ specification
|
||||
* does not allow template subclass members to access members of the parent that
|
||||
* do not depend on the template parameter.
|
||||
*/
|
||||
template <typename T>
|
||||
class smart_array_ptr
|
||||
{
|
||||
public:
|
||||
typedef T data_type;
|
||||
typedef T *ptr_type;
|
||||
typedef const T *const_ptr_type;
|
||||
typedef T &ref_type;
|
||||
typedef const T &const_ref_type;
|
||||
|
||||
//! Default constuctor. Initialises with no pointer set.
|
||||
smart_array_ptr()
|
||||
: _p(0)
|
||||
{
|
||||
}
|
||||
|
||||
//! This constructor takes a pointer to the object to be deleted.
|
||||
smart_array_ptr(ptr_type p)
|
||||
: _p(p)
|
||||
{
|
||||
}
|
||||
|
||||
//! Destructor. If an array has been set, it will be deleted.
|
||||
//! Deletes the array using safe_delete().
|
||||
virtual ~smart_array_ptr() { safe_delete(); }
|
||||
//! Return the current pointer value.
|
||||
ptr_type get() { return _p; }
|
||||
//! Return the const form of the current pointer value.
|
||||
const_ptr_type get() const { return _p; }
|
||||
//! Change the pointer value, or set if if the default constructor was used.
|
||||
//! If a pointer had previously been associated with the object, and \a p is
|
||||
//! different than that previous pointer, it will be deleted before taking
|
||||
//! ownership of \a p. If this is not desired, call reset() beforehand.
|
||||
void set(ptr_type p)
|
||||
{
|
||||
if (_p && p != _p)
|
||||
{
|
||||
safe_delete();
|
||||
}
|
||||
_p = p;
|
||||
}
|
||||
|
||||
//! Dissociates any previously set pointer value without deleting it.
|
||||
void reset() { _p = 0; }
|
||||
//! Dissociates a previously set pointer value, deleting it at the same time.
|
||||
void clear() { safe_delete(); }
|
||||
//! Forces immediate deletion of the object. If you are planning on using
|
||||
//! this method, think about just using a normal pointer. It probably makes
|
||||
//! more sense.
|
||||
virtual void safe_delete()
|
||||
{
|
||||
if (_p)
|
||||
{
|
||||
delete[] _p;
|
||||
_p = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//! \name Operators
|
||||
//@{
|
||||
|
||||
//! Makes the object transparent as the template type.
|
||||
operator ptr_type() { return _p; }
|
||||
//! Const version of the pointer operator.
|
||||
operator const_ptr_type() const { return _p; }
|
||||
//! Makes the object transparent as a reference of the template type.
|
||||
operator ref_type() { return *_p; }
|
||||
//! Const version of the reference operator.
|
||||
operator const_ref_type() const { return *_p; }
|
||||
//! Returns a boolean indicating whether the object has a pointer set or not.
|
||||
operator bool() const { return _p != 0; }
|
||||
//! To allow setting the pointer directly. Equivalent to a call to set().
|
||||
smart_array_ptr<T> &operator=(const_ptr_type p)
|
||||
{
|
||||
set(const_cast<ptr_type>(p));
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Another operator to allow you to treat the object just like a pointer.
|
||||
ptr_type operator->() { return _p; }
|
||||
//! Another operator to allow you to treat the object just like a pointer.
|
||||
const_ptr_type operator->() const { return _p; }
|
||||
//! Indexing operator.
|
||||
ref_type operator[](unsigned index) { return _p[index]; }
|
||||
//! Indexing operator.
|
||||
const_ref_type operator[](unsigned index) const { return _p[index]; }
|
||||
// //! Pointer dereferencing operator.
|
||||
// ref_type operator * () const { return *_p; }
|
||||
//
|
||||
// //! Const version of the pointer dereference operator.
|
||||
// const_ref_type operator * () const { return *_p; }
|
||||
|
||||
//@}
|
||||
|
||||
protected:
|
||||
ptr_type _p; //!< The wrapped pointer.
|
||||
};
|
||||
|
||||
#endif // _smart_ptr_h_
|
||||
38
apps/elftosb/common/stdafx.cpp
Normal file
38
apps/elftosb/common/stdafx.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Freescale Semiconductor, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* o Redistributions of source code must retain the above copyright notice, this list
|
||||
* of conditions and the following disclaimer.
|
||||
*
|
||||
* o Redistributions in binary form must reproduce the above copyright notice, this
|
||||
* list of conditions and the following disclaimer in the documentation and/or
|
||||
* other materials provided with the distribution.
|
||||
*
|
||||
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// stdafx.cpp : source file that includes just the standard includes
|
||||
// elftosb.pch will be the pre-compiled header
|
||||
// stdafx.obj will contain the pre-compiled type information
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
// TODO: reference any additional headers you need in STDAFX.H
|
||||
// and not in this file
|
||||
100
apps/elftosb/common/stdafx.h
Normal file
100
apps/elftosb/common/stdafx.h
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Freescale Semiconductor, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* o Redistributions of source code must retain the above copyright notice, this list
|
||||
* of conditions and the following disclaimer.
|
||||
*
|
||||
* o Redistributions in binary form must reproduce the above copyright notice, this
|
||||
* list of conditions and the following disclaimer in the documentation and/or
|
||||
* other materials provided with the distribution.
|
||||
*
|
||||
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef stdafx_h_
|
||||
#define stdafx_h_
|
||||
|
||||
// stdafx.h : include file for standard system include files,
|
||||
// or project specific include files that are used frequently, but
|
||||
// are changed infrequently
|
||||
//
|
||||
|
||||
// Default to external release.
|
||||
#ifndef SGTL_INTERNAL
|
||||
#define SGTL_INTERNAL 0
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
|
||||
#if defined(WIN32)
|
||||
//#include <tchar.h>
|
||||
|
||||
// define this macro for use in VC++
|
||||
#if !defined(__LITTLE_ENDIAN__)
|
||||
#define __LITTLE_ENDIAN__ 1
|
||||
#endif // !defined(__LITTLE_ENDIAN__)
|
||||
#endif // defined(WIN32)
|
||||
|
||||
#if defined(Linux)
|
||||
// For Linux systems only, types.h only defines the signed
|
||||
// integer types. This is not professional code.
|
||||
// Update: They are defined in the header files in the more recent version of redhat enterprise gcc.
|
||||
//#include "/usr/include/sys/types.h"
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
// typedef unsigned long uint32_t;
|
||||
// typedef unsigned short uint16_t;
|
||||
// typedef unsigned char uint8_t;
|
||||
|
||||
//#define TCHAR char
|
||||
//#define _tmain main
|
||||
|
||||
// give a default endian in case one is not defined on Linux (it should be, though)
|
||||
#if !defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)
|
||||
#define __LITTLE_ENDIAN__ 1
|
||||
#endif // !defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)
|
||||
|
||||
#endif // defined(Linux)
|
||||
|
||||
// gcc on Mac OS X
|
||||
#if defined(__GNUC__) && (defined(__APPLE_CPP__) || defined(__APPLE_CC__) || defined(__MACOS_CLASSIC__))
|
||||
#include <TargetConditionals.h>
|
||||
|
||||
#if defined(TARGET_RT_LITTLE_ENDIAN) && TARGET_RT_LITTLE_ENDIAN
|
||||
#if !defined(__LITTLE_ENDIAN__)
|
||||
#define __LITTLE_ENDIAN__
|
||||
#endif
|
||||
#elif defined(TARGET_RT_BIG_ENDIAN) && TARGET_RT_BIG_ENDIAN
|
||||
#if !defined(__BIG_ENDIAN__)
|
||||
#define __BIG_ENDIAN__
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(TRUE)
|
||||
#define TRUE 1
|
||||
#endif // !defined(TRUE)
|
||||
|
||||
#if !defined(FALSE)
|
||||
#define FALSE 0
|
||||
#endif // !defined(FALSE)
|
||||
|
||||
#endif // stdafx_h_
|
||||
Reference in New Issue
Block a user