Training courses

Kernel and Embedded Linux

Bootlin training courses

Embedded Linux, kernel,
Yocto Project, Buildroot, real-time,
graphics, boot time, debugging...

Bootlin logo

Elixir Cross Referencer

/*
 * 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 & section)
{
	return isSectionFilled(section.sh_addr, section.sh_size);
}