srcanamdw/appdep/src/appdep_cache.cpp
author noe\swadi
Sat, 09 Jan 2010 10:04:12 +0530
changeset 0 509e4801c378
permissions -rw-r--r--
1. Copyrights changed to EPL 2. Feature updates mentioned in release notes.

/*
* Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies). 
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:  Cache handling routines 
*
*/


#include "appdep.hpp"


// ----------------------------------------------------------------------------------------------------------

void ReadDataFromSymbolTablesCache(target& a_target)
{
	string line;
	
	ifstream symtabcachef(a_target.st_cache_path.c_str());
    if (!symtabcachef.is_open())
    {
        cerr << "Warning: Regenerating corrupted cache of target " << a_target.name << endl;
        a_target.cache_files_valid = false;
        _some_cache_needs_update = true;
        return;    
    }	
	
	getline(symtabcachef, line);
	if (line != CACHE_ST_HEADER)
    {
        cerr << "Warning: Regenerating corrupted cache of target " << a_target.name  << endl;
        a_target.cache_files_valid = false;  
        _some_cache_needs_update = true;
    }
    else
    {     
        // loop through all lines in the file
        while(!symtabcachef.eof())
        {
            getline(symtabcachef, line);
            
            if (line.length() > 0 && line[0] != CACHE_COMMENT_CHAR)
            {
                // first entry is the directory|filename|modification_time|symbol_table_size , eg
                // x:\epoc32\release\armv5\urel\|avkon.dll|1160666488|178
                string::size_type delim1 = line.find(CACHE_SEP, 0);
                string::size_type delim2 = line.find(CACHE_SEP, delim1+1);
                string::size_type delim3 = line.find(CACHE_SEP, delim2+1);

                import_library_info lib_info;
                lib_info.directory = line.substr(0, delim1);
                lib_info.filename = line.substr(delim1+1, delim2-delim1-1);
                lib_info.mod_time = Str2Int( line.substr(delim2+1, delim3-delim2-1) );
                unsigned int symbol_table_size = Str2Int( line.substr(delim3+1, line.length()-delim3-1) );
                
                // get symbol table
                vector<string> symbol_table; 
                for (unsigned int j=0; j<symbol_table_size; j++)
                {
                    getline(symtabcachef, line);
                    symbol_table.push_back( line );
                }
                
                lib_info.symbol_table = symbol_table;
                
                // append binary info to the vectory
                a_target.import_libraries.push_back( lib_info );
            }            
        }
        
        // check that the last line of the file contains the footer of the cache
        if (line != CACHE_FOOTER)
        {
            cerr << "Warning: Regenerating corrupted cache of target " << a_target.name  << endl;
            a_target.import_libraries.clear();
            a_target.cache_files_valid = false;  
            _some_cache_needs_update = true;
        }
    }
    
    symtabcachef.close();  
}

// ----------------------------------------------------------------------------------------------------------

void ReadDataFromDependenciesCache(target& a_target)
{
    string line;
        	
    // read data from the dependencies cache file
	ifstream depcachef(a_target.dep_cache_path.c_str());
    if (!depcachef.is_open())
    {
        cerr << "Warning: Regenerating corrupted cache of target " << a_target.name << endl;
        a_target.cache_files_valid = false;
        _some_cache_needs_update = true;
        return;    
    }	
	
	getline(depcachef, line);
	if (line != CACHE_DEP_HEADER)
    {
        cerr << "Warning: Regenerating corrupted cache of target " << a_target.name  << endl;
        a_target.cache_files_valid = false;  
        _some_cache_needs_update = true;
    }
    else
    {     
        // loop through all lines in the file
        while(!depcachef.eof())
        {
            getline(depcachef, line);
            
            if (line.length() > 0 && line[0] != CACHE_COMMENT_CHAR)
            {
                // first entry is the directory|filename|binary_format|uid1|uid2|uid3|secureid|vendorid|capabilities|min_heap_size|max_heap_size|stack_size|modification_time|number_of_dependencies , eg
                // x:\epoc32\release\armv5\urel\|about.exe|EPOC Exe for ARMV4 CPU|0x1000007a|0x100039ce|0x10005a22|0x10005a22|0x101fb657|782384|4096|1048576|8192|1160666488|11
                string::size_type delim1 = line.find(CACHE_SEP, 0);
                string::size_type delim2 = line.find(CACHE_SEP, delim1+1);
                string::size_type delim3 = line.find(CACHE_SEP, delim2+1);
                string::size_type delim4 = line.find(CACHE_SEP, delim3+1);
                string::size_type delim5 = line.find(CACHE_SEP, delim4+1);
                string::size_type delim6 = line.find(CACHE_SEP, delim5+1);
                string::size_type delim7 = line.find(CACHE_SEP, delim6+1);
                string::size_type delim8 = line.find(CACHE_SEP, delim7+1);
                string::size_type delim9 = line.find(CACHE_SEP, delim8+1);
                string::size_type delim10 = line.find(CACHE_SEP, delim9+1);
                string::size_type delim11 = line.find(CACHE_SEP, delim10+1);
                string::size_type delim12 = line.find(CACHE_SEP, delim11+1);
                string::size_type delim13 = line.find(CACHE_SEP, delim12+1);

                binary_info b_info;
                b_info.directory = line.substr(0, delim1);
                b_info.filename = line.substr(delim1+1, delim2-delim1-1);
                b_info.binary_format = line.substr(delim2+1, delim3-delim2-1);
                b_info.uid1 = line.substr(delim3+1, delim4-delim3-1);
                b_info.uid2 = line.substr(delim4+1, delim5-delim4-1);
                b_info.uid3 = line.substr(delim5+1, delim6-delim5-1);
                b_info.secureid = line.substr(delim6+1, delim7-delim6-1);
                b_info.vendorid = line.substr(delim7+1, delim8-delim7-1);
                b_info.capabilities = Str2Int( line.substr(delim8+1, delim9-delim8-1) );
                b_info.min_heap_size = Str2Int( line.substr(delim9+1, delim10-delim9-1) );
                b_info.max_heap_size = Str2Int( line.substr(delim10+1, delim11-delim10-1) );
                b_info.stack_size = Str2Int( line.substr(delim11+1, delim12-delim11-1) );
                b_info.mod_time = Str2Int( line.substr(delim12+1, delim13-delim12-1) );
                unsigned int number_of_deps = Str2Int( line.substr(delim13+1, line.length()-delim13-1) );
                
                vector<dependency> deps; 
                for (unsigned int j=0; j<number_of_deps; j++)
                {
                    getline(depcachef, line);
                    
                    // second type entry is filename|number_of_imports , eg
                    // APPARC.DLL|6
                    string::size_type delim1 = line.find(CACHE_SEP, 0);
                    
                    dependency dep;
                    dep.filename = line.substr(0, delim1);
                    unsigned int number_of_imports = Str2Int( line.substr(delim1+1, line.length()-delim1-1) );
                    
                    vector<import> imps;
                    for (unsigned int k=0; k<number_of_imports; k++)
                    {
                        getline(depcachef, line);
                        
                        // third type on entry is funcpos|funcname|is_vtable|vtable_offset, eg
                        // 121|CApaDocument::Capability() const|0|0
                        string::size_type delim1 = line.find(CACHE_SEP, 0);
                        string::size_type delim2 = line.find(CACHE_SEP, delim1+1);
                        string::size_type delim3 = line.find(CACHE_SEP, delim2+1);
                        
                        import imp;
                        imp.funcpos = Str2Int( line.substr(0, delim1) );
                        imp.funcname = line.substr(delim1+1, delim2-delim1-1);
                        imp.is_vtable = Str2Int( line.substr(delim2+1, delim3-delim2-1) );
                        imp.vtable_offset = Str2Int( line.substr(delim3+1, line.length()-delim3-1) );
                        
                        // append to the import info vector
                        imps.push_back( imp );
                    }                     
                    
                    // now we have import info too
                    dep.imports = imps;
                    
                    // append to the deps info vector
                    deps.push_back( dep );
                                    
                }
                // now we have the dep info too
                b_info.dependencies = deps;
                
                // apppend binary info to the vector
                a_target.binaries.push_back( b_info );
            }            
        }

        // check that the last line of the file contains the footer of the cache
        if (line != CACHE_FOOTER)
        {
            cerr << "Warning: Regenerating corrupted cache of target " << a_target.name  << endl;
            a_target.binaries.clear();
            a_target.cache_files_valid = false;  
            _some_cache_needs_update = true;
        }
    }
    depcachef.close();         
}

// ----------------------------------------------------------------------------------------------------------

void GetDataFromImportTables(target& a_target)
{
    // read data from import libraries if needed
    for (unsigned int i=0; i<a_target.lib_files.size(); i++)
    {
        bool is_new_file = true;

        vector<string> symbol_table;

        if (_cl_print_debug)
            cerr << "Processing " << a_target.release_lib_dir << a_target.lib_files.at(i) << "...";

        // if not generating a clean cache, check if this file was already in the cache 
        if (!_cl_generate_clean_cache)
        {
            // first try to find existing file
            bool update_file = false;
            int position = 0;
            
            for (unsigned int j=0; j<a_target.import_libraries.size(); j++)
            {
                // check if names match
                if (StringICmpFileNamesWithoutExtension(a_target.lib_files.at(i), a_target.import_libraries.at(j).filename) == 0)
                {
                    // the file was already found from the cache
                    is_new_file = false;
                    
                    // compare modification times
                    struct stat stat_p;
                    stat((a_target.release_lib_dir + a_target.lib_files.at(i)).c_str(), &stat_p); // get new stats
                    
                    if (!TimestampsMatches(a_target.import_libraries.at(j).mod_time, stat_p.st_mtime))
                    {
                        // time stamps are different so needs to update the file
                        update_file = true;
                        position = j;                         
                    }
                    
                    // there can't be anymore same names, so break the loop anyway
                    break;
                }
            }

            // get the new data
            if (update_file)
            {
                a_target.cache_files_valid = false;  // cache files on disk must be rewritten
                
                import_library_info& lib_info = a_target.import_libraries.at(position);
                lib_info.directory = a_target.release_lib_dir;
                                 
                if (_cl_use_gcc)
                {
                    GetSymbolTableWithNM(_gcc_nm_location, a_target.release_lib_dir, a_target.lib_files.at(i), symbol_table);
                }
                else if (_cl_use_gcce)
                {
                    if (_cl_use_libs)
                    {
                        GetSymbolTableWithNM(_gcce_nm_location, a_target.release_lib_dir, a_target.lib_files.at(i), symbol_table);
                    }
                    else
                    {
                        GetSymbolTableWithReadelf(_gcce_readelf_location, _gcce_cfilt_location, a_target.release_lib_dir, a_target.lib_files.at(i), symbol_table);
                    }
                }
                else if (_cl_use_rvct)
                {
                    if (_cl_use_libs)
                    {
                        GetSymbolTableWithArmar(_rvct_armar_location, _rvct_cfilt_location, a_target.release_lib_dir, a_target.lib_files.at(i), symbol_table);
                    }
                    else
                    {
                        GetSymbolTableWithFromelf(_rvct_fromelf_location, _rvct_cfilt_location, a_target.release_lib_dir, a_target.lib_files.at(i), symbol_table);
                    }
                }
                
                lib_info.symbol_table = symbol_table;
                
                // get statistics of the file and set the modification time
                struct stat stat_p;
                stat((a_target.release_lib_dir + a_target.lib_files.at(i)).c_str(), &stat_p);
                lib_info.mod_time = stat_p.st_mtime;
                
                // record changed import libraries
                _changed_import_libraries.push_back( lib_info );
            }
        }
        
        // this is a new file, get info and append it to the vector
        if (is_new_file)
        {
            a_target.cache_files_valid = false;  // cache files on disk must be rewritten

            // get the symbol tables of the library
            if (_cl_use_gcc)
            {
                GetSymbolTableWithNM(_gcc_nm_location, a_target.release_lib_dir, a_target.lib_files.at(i), symbol_table);
            }
            else if (_cl_use_gcce)
            {
                if (_cl_use_libs)
                {
                    GetSymbolTableWithNM(_gcce_nm_location, a_target.release_lib_dir, a_target.lib_files.at(i), symbol_table);
                }
                else
                {
                    GetSymbolTableWithReadelf(_gcce_readelf_location, _gcce_cfilt_location, a_target.release_lib_dir, a_target.lib_files.at(i), symbol_table);
                }
            }
            else if (_cl_use_rvct)
            {
                if (_cl_use_libs)
                {
                    GetSymbolTableWithArmar(_rvct_armar_location, _rvct_cfilt_location, a_target.release_lib_dir, a_target.lib_files.at(i), symbol_table);
                }
                else
                {
                    GetSymbolTableWithFromelf(_rvct_fromelf_location, _rvct_cfilt_location, a_target.release_lib_dir, a_target.lib_files.at(i), symbol_table);
                }
            }
            
            // get statistics of the file
            struct stat stat_p;
            stat((a_target.release_lib_dir + a_target.lib_files.at(i)).c_str(), &stat_p);
            
            // create a new entry to list of all import libraries
            import_library_info lib_info;
            lib_info.directory = a_target.release_lib_dir;
            lib_info.filename = a_target.lib_files.at(i);
            lib_info.mod_time = stat_p.st_mtime;
            lib_info.symbol_table = symbol_table;
            
            a_target.import_libraries.push_back( lib_info );
        }         
        if (_cl_print_debug)
            cerr << "OK" << endl;
        else
            ShowProgressInfo(_current_progress_percentage, _current_progress, _max_progress, false);
    }
}

// ----------------------------------------------------------------------------------------------------------

void GetDataFromBinaries(target& a_target)
{
    // read data from binaries
    for (unsigned int i=0; i<a_target.bin_files.size(); i++)
    {
        bool is_new_file = true;

        if (_cl_print_debug)
            cerr << "Processing " << a_target.release_bin_dir << a_target.bin_files.at(i) << "...";

        // if not generating a clean cache, check if this file was already in the cache 
        if (!_cl_generate_clean_cache)
        {
            // first try to find existing file
            bool update_file = false;
            int position = 0;
            
            for (unsigned int j=0; j<a_target.binaries.size(); j++)
            {
                // check if names match
                if (StringICmp(a_target.bin_files.at(i).c_str(), a_target.binaries.at(j).filename.c_str()) == 0)
                {
                    is_new_file = false;

                    // compare modification times
                    struct stat stat_p;
                    stat((a_target.release_bin_dir + a_target.bin_files.at(i)).c_str(), &stat_p); // get new stats
                    
                    if (!TimestampsMatches(a_target.binaries.at(j).mod_time, stat_p.st_mtime))
                    {
                        // time stamps are different so needs to update the file
                        update_file = true;
                        position = j;   
                        break; 
                    }
                    
                    // the entry also needs to be updated if any import library which this binary has dependency on has changed
                    for (unsigned int k=0; k<_changed_import_libraries.size(); k++)
                    {
                        for (unsigned int p=0; p<a_target.binaries.at(j).dependencies.size(); p++)
                        {
                            // check for file name match
                            if (StringICmpFileNamesWithoutExtension(a_target.binaries.at(j).dependencies.at(p).filename, _changed_import_libraries.at(k).filename) == 0)
                            {
                                update_file = true;
                                position = j;   
                                break;
                            }
                        }

                        // no need to loop anymore if the file needs update
                        if (update_file)
                            break;
                    }
                    
                    // there can't be anymore same names, so break the loop anyway
                    break;
                }
            }

            // get the new data
            if (update_file)
            {
                a_target.cache_files_valid = false;  // cache files on disk must be rewritten
                
                binary_info& b_info = a_target.binaries.at(position);
                b_info.directory = a_target.release_bin_dir;
                                 
                GetImportTableWithPetran(_petran_location, b_info);
                
                // get statistics of the file and set the modification time
                struct stat stat_p;
                stat((a_target.release_bin_dir + a_target.bin_files.at(i)).c_str(), &stat_p);
                b_info.mod_time = stat_p.st_mtime;
            }
        }

        // this is a new file, get info and append it to the vector
        if (is_new_file)
        {            
            a_target.cache_files_valid = false;  // cache files on disk must be rewritten

            binary_info b_info;
            b_info.directory = a_target.release_bin_dir;
            b_info.filename = a_target.bin_files.at(i);
                             
            GetImportTableWithPetran(_petran_location, b_info);
            
            // get statistics of the file and set the modification time
            struct stat stat_p;
            stat((a_target.release_bin_dir + a_target.bin_files.at(i)).c_str(), &stat_p);
            b_info.mod_time = stat_p.st_mtime;
            
            // create a new entry to list of all binary files
            a_target.binaries.push_back( b_info );
        }
        
        if (_cl_print_debug)
            cerr << "OK" << endl;
        else
            ShowProgressInfo(_current_progress_percentage, _current_progress, _max_progress, false);
    }

}

// ----------------------------------------------------------------------------------------------------------

void WriteDataToSymbolTableCacheFile(const target& a_target)
{
    // open the cache file for writing
    ofstream symtabcachef(a_target.st_cache_path.c_str(), ios::trunc);
    if (!symtabcachef.is_open())
    {
        symtabcachef.close();
		cerr << endl << "ERROR: Cannot open " << a_target.st_cache_path << " for writing!" << endl;
		cerr << "Please check that the directory exists and there are no write permission problems" << endl;
		exit(EXIT_CANNOT_WRITE_TO_CACHE_FILE);
    }
            
    // write data to the cache file
    symtabcachef << CACHE_ST_HEADER << endl;
    
    for (unsigned int i=0; i<a_target.import_libraries.size(); i++)
    {
        vector<string> symbol_table = a_target.import_libraries.at(i).symbol_table;

        symtabcachef << a_target.import_libraries.at(i).directory << CACHE_SEP << a_target.import_libraries.at(i).filename << CACHE_SEP
                     << a_target.import_libraries.at(i).mod_time << CACHE_SEP << symbol_table.size() << endl;
        
        for (unsigned int j=0; j<symbol_table.size(); j++)
        {
            symtabcachef << symbol_table.at(j) << endl;
        }
    }

    // write footer, note that there is no eol char
    symtabcachef << CACHE_FOOTER;

    symtabcachef.close(); 
}

// ----------------------------------------------------------------------------------------------------------

void WriteDataToDependenciesCacheFile(const target& a_target)
{
    // open the cache file for writing
    ofstream depcachef(a_target.dep_cache_path.c_str(), ios::trunc);
    if (!depcachef.is_open())
    {
        depcachef.close();
		cerr << endl << "ERROR: Cannot open " << a_target.dep_cache_path << " for writing!" << endl;
		cerr << "Please check that the directory exists and there are no write permission problems" << endl;
		exit(EXIT_CANNOT_WRITE_TO_CACHE_FILE);
    }

    // write data to the cache file
    depcachef << CACHE_DEP_HEADER << endl;
    
    for (unsigned int i=0; i<a_target.binaries.size(); i++)
    {
        vector<dependency> deps = a_target.binaries.at(i).dependencies;

        depcachef << a_target.binaries.at(i).directory << CACHE_SEP << a_target.binaries.at(i).filename << CACHE_SEP
                  << a_target.binaries.at(i).binary_format << CACHE_SEP << a_target.binaries.at(i).uid1 << CACHE_SEP
                  << a_target.binaries.at(i).uid2 << CACHE_SEP << a_target.binaries.at(i).uid3 << CACHE_SEP
                  << a_target.binaries.at(i).secureid << CACHE_SEP << a_target.binaries.at(i).vendorid << CACHE_SEP
                  << a_target.binaries.at(i).capabilities << CACHE_SEP << a_target.binaries.at(i).min_heap_size << CACHE_SEP
                  << a_target.binaries.at(i).max_heap_size << CACHE_SEP << a_target.binaries.at(i).stack_size << CACHE_SEP
                  << a_target.binaries.at(i).mod_time << CACHE_SEP << deps.size() << endl;
        
        for (unsigned int j=0; j<deps.size(); j++)
        {
            vector<import> imps = deps.at(j).imports;

            depcachef << deps.at(j).filename << CACHE_SEP << imps.size() << endl;
            
            for (unsigned int k=0; k<imps.size(); k++)
            {
                depcachef << imps.at(k).funcpos << CACHE_SEP << imps.at(k).funcname << CACHE_SEP << imps.at(k).is_vtable
                          << CACHE_SEP << imps.at(k).vtable_offset << endl;   
            }
        }
    }

    // write footer, note that there is no eol char
    depcachef << CACHE_FOOTER;

    depcachef.close();  
}

// ----------------------------------------------------------------------------------------------------------