Back to index

lightning-sunbird  0.9+nobinonly
gc_fragments.cpp
Go to the documentation of this file.
00001 /*
00002        gc_fragments.cpp
00003  */
00004 
00005 #include "gc_fragments.h"
00006 #include "sym_file.h"
00007 #include "gc.h"
00008 #include "MetroNubUtils.h"
00009 
00010 #include <string.h>
00011 
00012 struct CodeLocation {
00013        CodeLocation* mNext;
00014        char* mCodeAddr;
00015        UInt32 mFileOffset;
00016        char mSymbolName[256];
00017        char mFileName[256];
00018        
00019        CodeLocation() : mNext(NULL), mCodeAddr(NULL), mFileOffset(0)
00020        {
00021               mFileName[0] = '\0';
00022        }
00023 };
00024 
00025 static const kCodeLocationCacheSize = 256;
00026 
00027 struct CodeLocationCache {
00028        CodeLocation mEntries[kCodeLocationCacheSize];
00029        CodeLocation* mLocations;
00030        CodeLocation** mLastLink;
00031 
00032        CodeLocationCache();
00033 
00034        CodeLocation* findLocation(char* codeAddr);
00035        void saveLocation(char* codeAddr, char symbolName[256], char fileName[256], UInt32 fileOffset);
00036 };
00037 
00038 CodeLocationCache::CodeLocationCache()
00039        :      mLocations(NULL), mLastLink(&mLocations)
00040 {
00041        // link all of the locations together in a list.
00042        int offset = kCodeLocationCacheSize;
00043        while (offset > 0) {
00044               CodeLocation* location = &mEntries[--offset];
00045               location->mNext = mLocations;
00046               mLocations = location;
00047        }
00048 }
00049 
00050 CodeLocation* CodeLocationCache::findLocation(char* codeAddr)
00051 {
00052        CodeLocation** link = &mLocations;
00053        CodeLocation* location = *link;
00054        while (location != NULL && location->mCodeAddr != NULL) {
00055               if (location->mCodeAddr == codeAddr) {
00056                      // move it to the head of the list.
00057                      if (location != mLocations) {
00058                             *link = location->mNext;
00059                             location->mNext = mLocations;
00060                             mLocations = location;
00061                      }
00062                      return location;
00063               }
00064               link = &location->mNext;
00065               location = *link;
00066               // maintain pointer to the last element in list for fast insertion.
00067               if (location != NULL)
00068                      mLastLink = link;
00069        }
00070        return NULL;
00071 }
00072 
00073 void CodeLocationCache::saveLocation(char* codeAddr, char symbolName[256], char fileName[256], UInt32 fileOffset)
00074 {
00075        CodeLocation** link = mLastLink;
00076        CodeLocation* location = *link;
00077        mLastLink = &mLocations;
00078        
00079        // move it to the head of the list.
00080        if (location != mLocations) {
00081               *link = location->mNext;
00082               location->mNext = mLocations;
00083               mLocations = location;
00084        }
00085        
00086        // save the specified location.
00087        location->mCodeAddr = codeAddr;
00088        location->mFileOffset = fileOffset;
00089        ::strcpy(location->mSymbolName, symbolName);
00090        ::strcpy(location->mFileName, fileName);
00091 }
00092 
00093 struct CodeFragment {
00094        CodeFragment* mNext;
00095        char* mDataStart;
00096        char* mDataEnd;
00097        char* mCodeStart;
00098        char* mCodeEnd;
00099        FSSpec mFragmentSpec;
00100        CodeLocationCache mLocations;
00101        sym_file* mSymbols;
00102        
00103        CodeFragment(char* dataStart, char* dataEnd,
00104                  char* codeStart, char* codeEnd,
00105                  const FSSpec* fragmentSpec);
00106 
00107        ~CodeFragment();
00108        
00109        void* operator new(size_t n) { return ::GC_malloc(n); }
00110        void operator delete(void* ptr) { return ::GC_free(ptr); }     
00111 };
00112 
00113 CodeFragment::CodeFragment(char* dataStart, char* dataEnd,
00114                            char* codeStart, char* codeEnd,
00115                            const FSSpec* fragmentSpec)
00116        :      mDataStart(dataStart), mDataEnd(dataEnd),
00117               mCodeStart(codeStart), mCodeEnd(codeEnd),
00118               mFragmentSpec(*fragmentSpec), mSymbols(NULL), mNext(NULL)
00119 {
00120        // need to eagerly open symbols file eagerly, otherwise we're in the middle of a GC!
00121        FSSpec symSpec = mFragmentSpec;
00122        UInt8 len = symSpec.name[0];
00123        symSpec.name[++len] = '.';
00124        symSpec.name[++len] = 'x';
00125        symSpec.name[++len] = 'S';
00126        symSpec.name[++len] = 'Y';
00127        symSpec.name[++len] = 'M';
00128        symSpec.name[0] = len;
00129 
00130        mSymbols = open_sym_file(&symSpec);
00131 }
00132 
00133 CodeFragment::~CodeFragment()
00134 {
00135        if (mSymbols) {
00136               close_sym_file(mSymbols);
00137               mSymbols = NULL;
00138        }
00139 }
00140 
00141 static CodeFragment* theFragments = NULL;
00142 
00143 static CodeFragment** find_fragment(char* codeAddr)
00144 {
00145        CodeFragment** link = &theFragments;
00146        CodeFragment* fragment = *link;
00147        while (fragment != NULL) {
00148               if (codeAddr >= fragment->mCodeStart && codeAddr < fragment->mCodeEnd)
00149                      return link;
00150               link = &fragment->mNext;
00151               fragment = *link;
00152        }
00153        return NULL;
00154 }
00155 
00156 void GC_register_fragment(char* dataStart, char* dataEnd,
00157                           char* codeStart, char* codeEnd,
00158                           const FSSpec* fragmentSpec)
00159 {
00160        // register the roots.
00161        GC_add_roots(dataStart, dataEnd);
00162 
00163        // create an entry for this fragment.
00164        CodeFragment* fragment = new CodeFragment(dataStart, dataEnd,
00165                                                  codeStart, codeEnd,
00166                                                  fragmentSpec);
00167        if (fragment != NULL) {
00168               fragment->mNext = theFragments;
00169               theFragments = fragment;
00170        }
00171 }
00172 
00173 void GC_unregister_fragment(char* dataStart, char* dataEnd,
00174                             char* codeStart, char* codeEnd)
00175 {
00176        // try not to crash when running under the MW debugger.
00177        if (!AmIBeingMWDebugged()) {
00178               CodeFragment** link = find_fragment(codeStart);
00179               if (link != NULL) {
00180                      CodeFragment* fragment = *link;
00181                      *link = fragment->mNext;
00182                      delete fragment;
00183               }
00184        }
00185 
00186        // remove the roots.
00187        GC_remove_roots(dataStart, dataEnd);
00188 }
00189 
00190 int GC_address_to_source(char* codeAddr, char symbolName[256], char fileName[256], UInt32* fileOffset)
00191 {
00192        CodeFragment** link = find_fragment(codeAddr);
00193        if (link != NULL) {
00194               CodeFragment* fragment = *link;
00195               // always move this fragment to the head of the list, to speed up searches.
00196               if (theFragments != fragment) {
00197                      *link = fragment->mNext;
00198                      fragment->mNext = theFragments;
00199                      theFragments = fragment;
00200               }
00201               // see if this is a cached location.
00202               CodeLocation* location = fragment->mLocations.findLocation(codeAddr);
00203               if (location != NULL) {
00204                      ::strcpy(symbolName, location->mSymbolName);
00205                      ::strcpy(fileName, location->mFileName);
00206                      *fileOffset = location->mFileOffset;
00207                      return 1;
00208               }
00209               sym_file* symbols = fragment->mSymbols;
00210               if (symbols != NULL) {
00211                      if (get_source(symbols, UInt32(codeAddr - fragment->mCodeStart), symbolName, fileName, fileOffset)) {
00212                             // save this location in the per-fragment cache.
00213                             fragment->mLocations.saveLocation(codeAddr, symbolName, fileName, *fileOffset);
00214                             return 1;
00215                      }
00216               }
00217        }
00218        return 0;
00219 }