Provisional fix for bug 3508 - Persistent storage support breaks Linux compatibility.
Enables libnvmemmory.so to be built and dynamically linked on Linux and rom boot reports persistent storage image created OK, but ROM then crashes.
/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <boost/program_options.hpp>
namespace po = boost::program_options;
#include <boost/regex.hpp>
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
#include <iostream>
#include <iterator>
#include <string>
#include <map>
#include <set>
#include <ctype.h>
#include <cstdlib>
using namespace std;
#include "defs.h"
#include "romdetails.h"
#include "inputfile.h"
#include "elfromerror.h"
static inline void downcase(std::string & s){
for (std::string::iterator i = s.begin(); i != s.end(); i++)
*i = tolower(*i);
}
static int required_option(const po::variables_map& vm, const char* option){
if (vm.count(option) == 0 || vm[option].defaulted()) {
cerr << "Error: option \'" << option << "\' required.\n";
return 1;
}
return 0;
}
static int either_or_required(const po::variables_map& vm, const char* option1, const char* option2){
if ((vm.count(option1) == 0 || vm[option1].defaulted()) &&
(vm.count(option2) == 0 || vm[option2].defaulted())) {
cerr << "Error: either option \'" << option1 << "\' or option \'" << option2 <<"\' required.\n";
return 1;
}
return 0;
}
RomDetails * ProcessOptions(int ac, char* av[]) {
RomDetails * details = new RomDetails;
int errors = 0;
try {
string phys_addr;
po::options_description desc(" Command Line Only");
desc.add_options()
("help,h", "produce help message")
("config-file,c", po::value<string>(), "pathname of config file "
"(overrides default of elf4rom.cfg and value "
"of ELF4ROM_CFG_FILE environment variable)")
;
po::options_description config(" Command Line and Configuration File");
config.add_options()
("board-name,b", po::value<string>(&details->iBoardName), "name of board targeted e.g. versatilepb")
("debug,d", po::value< vector<string> >(&details->iTargetFiles)->multitoken()->composing(),
"collect ELF and DWARF data from the listed files")
("drive,D", po::value<string>(&details->iDrive), "drive on which to find ELF files")
("exclude,e", po::value< vector<string> >(&details->iExcludeFiles)->multitoken()->composing(),
"exclude collection of ELF and DWARF data from the listed files")
("input,i", po::value<string>(&details->iRomFile), "pathname of ROM image")
("logfile,l", po::value<string>(&details->iLogFile), "pathname of ROMBUILD log file")
("no-dwarf,n", po::bool_switch(&details->iNoDwarf), "suppress generatation of DWARF in output"
" (prevents source level debugging but saves time and space)")
("output,o", po::value<string>(&details->iElfRomFile), "pathname of output file")
// lexical_cast doesn't understand <LinearAddress> even though its just a typedef
// for unsigned int
("physical-address,p", po::value<string>(&phys_addr), "physical address of ROM on device. Overrides board-name")
("search,s", po::bool_switch(&details->iSearch), "search for ELF files in build directory if .sym file not "
"found in release directory")
("strip,S", po::bool_switch(&details->iStrip), "suppress generation of symbol table and DWARF in output"
" (useful to produce a 'loadable' ELF image for e.g. a simulator)")
("trace,t", po::bool_switch(&details->iTrace), "switch on trace")
;
po::options_description cmdline_options;
cmdline_options.add(desc).add(config);
po::options_description config_file_options;
config_file_options.add(config);
po::variables_map vm;
//po::store(po::parse_command_line(ac, av, desc), vm);
po::store(po::command_line_parser(ac, av).options(cmdline_options).run(), vm);
char * cfgFile = "elf4rom.cfg";
if (vm.count("config-file")) {
char * xcfgFile = (char *)(vm["config-file"].as<string>().c_str());
fs::path cfgpath(xcfgFile);
if (fs::exists(cfgpath)) {
cfgFile = xcfgFile;
} else {
cerr << "Warning: specified config file " << xcfgFile << " not found: will not attempt to use default.\n";
}
} else {
char * envCfgFile = getenv("ELF4ROM_CFG_FILE");
if (envCfgFile != NULL)
cfgFile = envCfgFile;
}
ifstream ifs(cfgFile);
store(parse_config_file(ifs, config_file_options), vm);
po::notify(vm);
if (vm.count("help")) {
cout << "elf4rom [option]";
cout << cmdline_options << "\n";
delete details;
exit(EXIT_SUCCESS) ;
}
errors += required_option(vm, "input");
errors += required_option(vm, "logfile");
errors += required_option(vm, "output");
errors += either_or_required(vm, "board-name", "physical-address");
if (vm.count("physical-address")){
char *f;
const char * p = phys_addr.c_str();
details->iRomPhysAddr = strtoul(p ,&f , 16);
if (f == p){
cerr << "Error: invalid arg to --physical-address: " << phys_addr.c_str() << "\n";
exit(EXIT_FAILURE);
}
} else if (vm.count("board-name")){
// TODO: figure out address frmo board name
cerr << "Error: --board-name option not implemented yet\n";
exit(EXIT_FAILURE) ;
}
if (errors) {
cerr << "elf4rom [option]";
cerr << cmdline_options << "\n";
delete details;
exit(EXIT_FAILURE) ;
}
}
catch(exception& e) {
cerr << "error: " << e.what() << "\n";
exit(EXIT_FAILURE) ;
}
catch(...) {
cerr << "Exception of unknown type!\n";
exit(EXIT_FAILURE) ;
}
return details;
}
static bool VerifyLogFile(string::const_iterator & start, string::const_iterator & end, string::const_iterator & rest){
#if 0
// Look for somthing like the following
ROMBUILD - Rom builder V2.08 (Build 593)
Copyright (c) 1996-2007 Symbian Software Ltd.
or
ROMBUILD - Rom builder V2.08 (Build 596)
Copyright (c) 1996-2009 Nokia Corporation.
#endif
const char * banner = "ROMBUILD.*Rom builder.*Copyright.*";
boost::regex e(banner);
boost::match_results<string::const_iterator> what;
if (boost::regex_search(start, end, what, e)){
rest = what[0].second;
return true;
}
return false;
}
static void OffenceWarning (string & offender){
cerr << "Warning: The following section of the ROM Log appears corrupt:\n" << offender << "\n";
}
static inline unsigned int ConvertToUnsignedLong(string & s, string & offender){
char * endp;
const char * ss = s.c_str();
unsigned int res = strtoul(ss, &endp,16);
if (endp == ss)
OffenceWarning(offender);
return res;
}
static bool ProcessXIPFile(string::const_iterator & start, string::const_iterator & end,
string::const_iterator & rest, RomDetails * details){
const char * f =
"Processing file (\\S+)\\s*" // 1
"(\\[Primary\\]\\s*)?" // 2
"(\\[Secondary\\]\\s*)?" // 3
"(ELF File:\\s*\\S+\\s*)?" // 4
"(ELF MD5:\\s*\\S+\\s*)?" // 5
"Load Address:\\s+(\\S+)\\s*" // 6
"Size:\\s+\\S+\\s*"
"Uids:\\s+\\S+\\s+\\S+\\s+\\S+\\s+\\S+\\s*"
"Entry point:\\s+\\S+\\s*"
"Code start addr:\\s+(\\S+)\\s*" // 7
"Data start addr:\\s+(\\S+)\\s*" // 8
"DataBssLinearBase:\\s+(\\S+)\\s*" // 9
"Text size:\\s+\\S+\\s*"
"Code size:\\s+(\\S+)\\s*" // 10
"Data size:\\s+(\\S+)\\s*" // 11
"BssSize:\\s+(\\S+)\\s*" // 12
;
boost::regex e(f);
boost::match_results<string::const_iterator> what;
if (boost::regex_search(start, end, what, e)){
string filename(what[1].first, what[1].second);
string offender(what[0].first, what[0].second);
if (filename.size() == 0)
OffenceWarning(offender);
bool primary = what[2].matched;
if (what[2].matched){
primary = true;
}
const int kla = 6;
string ls(what[kla].first, what[kla].second);
LinearAddr load = ConvertToUnsignedLong(ls, offender);
const int kta = kla + 1;
string ts(what[kta].first, what[kta].second);
LinearAddr text = ConvertToUnsignedLong(ts, offender);
const int kda = kta + 1;
string ds(what[kda].first, what[kda].second);
LinearAddr data = ConvertToUnsignedLong(ds, offender);
const int kva = kda + 1;
string vds(what[kva].first, what[kva].second);
VirtualAddr vdata = ConvertToUnsignedLong(vds, offender);
const int kts = kva + 1;
string tss(what[kts].first, what[kts].second);
size_t textSize = ConvertToUnsignedLong(tss, offender);
const int kds = kts + 1;
string dss(what[kds].first, what[kds].second);
size_t fileDataSize = ConvertToUnsignedLong(dss, offender);
const int kbs = kds + 1;
string bsss(what[kbs].first, what[kbs].second);
size_t bssSize = ConvertToUnsignedLong(bsss, offender);
VirtualAddr bss = vdata + fileDataSize;
size_t memDataSize = fileDataSize + bssSize;
string elffile("");
details->iXIPFiles.push_back(XIPFileDetails(filename,
elffile,
load,
text,
textSize,
vdata,
fileDataSize,
data,
bss,
memDataSize));
if (primary)
new(&details->iPrimary)XIPFileDetails(filename,
elffile,
load,
text,
textSize,
vdata,
fileDataSize,
data,
bss,
memDataSize);
rest = what[0].second;
return true;
}
rest = start;
return false;
}
static void CheckXIPFiles(RomDetails * details, std::vector<string> & list){
for (std::vector<string>::iterator i = list.begin(); i != list.end(); i++) {
bool found = false;
for (RomDetails::XIPFileList::iterator j = details->iXIPFiles.begin(); j != details->iXIPFiles.end(); j++){
fs::path e32filePath(j->iE32File);
String e32FileName(e32filePath.leaf());
if ((*i) == e32FileName){
found = true;
break;
}
}
if (!found){
cerr << "WARNING: " << (*i) << " not found in ROM\n";
}
}
}
static void CheckDebugXIPFiles(RomDetails * details){
CheckXIPFiles(details, details->iTargetFiles);
}
static void CheckExcludeXIPFile(RomDetails * details){
CheckXIPFiles(details, details->iExcludeFiles);
}
static void ProcessXIPFiles(string::const_iterator & start, string::const_iterator & end,
string::const_iterator & rest, RomDetails * details){
while (ProcessXIPFile(start,end,rest,details)){
start = rest;
}
CheckDebugXIPFiles(details);
CheckExcludeXIPFile(details);
}
static void ProcessRomDetails(string::const_iterator & start, string::const_iterator & end,
string::const_iterator & rest, RomDetails * details){
const char * align = "Linear base address:\\s*([\\S]+)$";
boost::regex e(align);
boost::match_results<string::const_iterator> what;
if (boost::regex_search(start, end, what, e)){
string offender(what[0].first, what[0].second);
string lbas(what[1].first, what[1].second);
details->iRomBaseLinearAddr = ConvertToUnsignedLong(lbas, offender);
} else {
cerr << "Error: " << details->iLogFile << " not a valid ROM log file. Could not find Linear base address." << "\n";
exit(EXIT_FAILURE) ;
}
}
static fs::path FindBuildPath(RomDetails * details){
const string epoc32("epoc32");
const string builddir("build");
const string epocRoot(getenv("EPOCROOT"));
if (details->iDrive.size() > 0) {
string drive(details->iDrive);
if (drive.size() == 1){
drive += ":";
} else if (((drive.size() == 2) && (drive[drive.size()-1] != ':')) || (drive.size() > 2)){
cerr << "Error: Invalid drive specification: " << drive << "\n";
exit(EXIT_FAILURE) ;
}
fs::path buildpath(drive);
buildpath /= epocRoot;
buildpath /= epoc32;
buildpath /= builddir;
return buildpath;
}
fs::path primary_path(details->iPrimary.iE32File);
fs::path buildpath;
for (fs::path::iterator i = primary_path.begin(); i != primary_path.end(); i++){
string item(*i);
downcase(item);
buildpath /= item;
if (item == epoc32) {
buildpath /= builddir;
break;
}
}
return buildpath;
}
class PathCache {
public:
typedef std::map<string, string> PathMap;
PathCache(fs::path & apath):
iBuildPath(apath)
{
if (fs::exists(apath)){
fs::recursive_directory_iterator i(apath);
iCurrent = i;
}
}
bool FindPath(string & pattern, string & result);
fs::path & GetBuildPath() { return iBuildPath; }
private:
bool GetNextPath(string & path);
bool Filtered(fs::path & path);
private:
fs::path iBuildPath;
fs::recursive_directory_iterator iCurrent;
fs::recursive_directory_iterator iEnd;
PathMap iPathMap;
static const std::string filters;
};
bool PathCache::Filtered(fs::path & apath){
std::string ext(fs::extension(apath));
downcase(ext);
if (ext.size() > 0){
if (filters.find(ext) != std::string::npos)
return true;
}
return false;
}
bool PathCache::GetNextPath(string & path){
for (; iCurrent != iEnd; ++iCurrent ){
if (fs::is_directory(iCurrent->status()))
continue;
fs::path candidate(iCurrent->path());
if (!Filtered(candidate)) {
path = candidate.string();
++iCurrent;
return true;
}
}
return false;
}
static void GetTarget(string & source, string & target){
fs::path t1(source);
fs::path::iterator s = t1.begin();
fs::path::iterator start = t1.end();
int n = 0;
for (; n < 3 && s != start; n++, start--){}
if (n < 3) {
warnx(0, "%s does not have 3 elements\n", source.c_str());
}
fs::path q;
for (; start != t1.end(); start++){
q /= fs::path(*start);
}
target = q.string();
downcase(target);
}
bool PathCache::FindPath(string & source, string & result){
string ss;
if (source.size() == 0) return false;
GetTarget(source, ss);
// now check the cache
PathMap::iterator res = iPathMap.find(ss);
if (res != iPathMap.end()){
result = res->second;
return true;
}
// otherwise iterate until we find a match
string candidate;
while (GetNextPath(candidate)){
downcase(candidate);
size_t n = candidate.rfind(ss);
if (n != string::npos){
size_t csize = candidate.size();
size_t sssize = ss.size();
if ((csize - sssize) == n){
// put it in cache anyway just in case its the primary
iPathMap[ss] = candidate;
result = candidate;
return true;
}
}
string x;
GetTarget(candidate, x);
iPathMap[x] = candidate;
}
return false;
}
const std::string PathCache::filters(
".cpp"
".h"
".mk"
".o"
".in"
".via"
".mbg"
".rsg"
".bat"
".make"
".def"
".armv5"
);
static bool FindSymFile(XIPFileDetails & detail, string & rootname){
fs::path buildpath(rootname);
fs::path e32path(detail.iE32File);
buildpath /= e32path;
// check for pre-RAPTOR .sym file
fs::path elfpath = fs::change_extension(buildpath, ".sym");
if (fs::exists(elfpath)) {
detail.iElfFile = elfpath.string();
return true;
}
// check for RAPTOR .sym file
fs::path symPath(buildpath.string() + ".sym");
if (fs::exists(symPath)) {
detail.iElfFile = symPath.string();
return true;
}
return false;
}
static void FindElfFile(XIPFileDetails & detail, PathCache & cache, bool search){
// see if there's a .sym file
string root(cache.GetBuildPath().root_name());
if (FindSymFile(detail, root)) return;
if (!search) {
cerr << "Warning: could not find ELF file for " << detail.iE32File << ".\n";
return;
}
string s(detail.iE32File);
string res;
if (s.size() == 0) return;
if (cache.GetBuildPath().string().empty()) return;
if (cache.FindPath(s, res)){
detail.iElfFile = res;
} else
cerr << "Warning: could not find ELF file for " << detail.iE32File << ".\n";
}
static void FindElfFiles(RomDetails * details){
fs::path buildroot = FindBuildPath(details);
PathCache cache(buildroot);
bool search = details->iSearch;
FindElfFile(details->iPrimary, cache, search);
for(RomDetails::XIPFileList::iterator i = details->iXIPFiles.begin(); i != details->iXIPFiles.end(); i++){
fs::path e32filePath(i->iE32File);
String e32FileName(e32filePath.leaf());
if (details->iTargetFiles.empty()) {
bool find = true;
for (std::vector<String>::iterator ef = details->iExcludeFiles.begin(); ef != details->iExcludeFiles.end(); ef++) {
fs::path excludePath(*ef);
String excludeFile(excludePath.leaf());
if (e32FileName == excludeFile) {
find = false;
break;
}
}
if (find)
FindElfFile(*i, cache, search);
} else {
for (std::vector<String>::iterator tf = details->iTargetFiles.begin(); tf != details->iTargetFiles.end(); tf++) {
fs::path targetPath(*tf);
String targetFile(targetPath.leaf());
if (e32FileName == targetFile) {
FindElfFile(*i, cache, search);
break;
}
}
}
}
}
RomDetails * ProcessRomDetails(RomDetails * details){
InputFile in(details->iLogFile);
char * data = in.GetData();
string logfile(data);
string::const_iterator start = logfile.begin();
string::const_iterator end = logfile.end();
string::const_iterator rest;
if (!VerifyLogFile(start, end , rest)) {
cerr << "error: " << details->iLogFile << " not a valid ROM log file." << "\n";
exit(EXIT_FAILURE) ;
}
ProcessXIPFiles(start,end,rest,details);
ProcessRomDetails(rest, end, rest, details);
FindElfFiles(details);
// TODO: make sure functions that return data allocated with new []
// have an appropriate return value so that delete [] can be used
delete [] data;
return details;
}