summaryrefslogtreecommitdiffstats
path: root/common/GHSSecInfo.cpp
blob: 300366cf0762839dfb3595f80f8bcf5135bb8cd7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/*
 * 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);
}