/* Adds (appends) a (string)value to an entry. * If value == NULL, the string "*NULL*" will be appended. * This function will do nothing if entry == NULL. */ static void a_lstAddEntryValueDo( a_lstEntry entry, char *value) { if (entry) { if (!entry->value) { entry->value = a_memStrdup(value); } else { const char *fill = ", "; char *newValue; if (!value) { value = "*NULL*"; } newValue = a_memAlloc(strlen(entry->value) + strlen(fill) + strlen(value) + 1); if (newValue) { strcpy(newValue, entry->value); strcat(newValue, fill); strcat(newValue, value); a_memFree(entry->value); entry->value = newValue; } } } }
/* Creates an apiObject and copies data from the lstObject * into it. Returns a pointer to this new object, or NULL * if the malloc failed. * This copy construction is required for keeping lstObject * (and a_lst for that matter) hidden to the outside. * Remember to free (using a_memfree()) the apiObject after * use. */ static a_apiObject a_apiLstObjectToApiObject( a_lstObject lstObject) { a_apiObject apiObject = a_memAlloc(sizeof(struct a_apiObject)); if (apiObject) { apiObject->objectAddress = lstObject->address; apiObject->referenceCount = lstObject->refCount; apiObject->alignment = lstObject->alignment; apiObject->size = lstObject->size; apiObject->ourSize = lstObject->ourSize; apiObject->objectName = a_memStrdup(lstObject->objectName); apiObject->typeName = a_memStrdup(lstObject->typeName); apiObject->typeDesc = a_memStrdup(lstObject->typeDesc); apiObject->value = a_memStrdup(lstObject->value); apiObject->note = a_memStrdup(lstObject->note); apiObject->occurrencesCount = lstObject->occurrencesCount; apiObject->typeRefsCount = lstObject->typeRefsCount; apiObject->dataRefsCount = lstObject->dataRefsCount; apiObject->unknRefsCount = lstObject->unknRefsCount; apiObject->refsDifference = lstObject->refsDifference; apiObject->refsToTypeCount = lstObject->refsToTypeCount; apiObject->refsToDataCount = lstObject->refsToDataCount; apiObject->refsToUnknCount = lstObject->refsToUnknCount; apiObject->occurrenceDiff = lstObject->occurrenceDiff; apiObject->objectKind = a_lstGetObjectKindChar(lstObject->kind); } return apiObject; }
/* Adds (appends) a note to an entry's note field. * If note == NULL, the string "*NULL*" will be appended. * This function will do nothing if entry == NULL. */ static void a_lstAddEntryNoteDo( a_lstEntry entry, char *note) { if (entry) { if (!entry->note) { entry->note = a_memStrdup(note); } else { const char *fill = ", "; char *newNote; if (!note) { note = "*NULL*"; } newNote = a_memAlloc(strlen(entry->note) + strlen(fill) + strlen(note) + 1); if (newNote) { strcpy(newNote, entry->note); strcat(newNote, fill); strcat(newNote, note); a_memFree(entry->note); entry->note = newNote; } } } }
/** * \brief * Creates a new HashTable * * This operation creates a new hash table and returns a pointer * to it. The table size refers to the number of elements to be * used in the internal array. The real array size used at * creation may differ from the given here. Due to optimilisation * reasons, the \a array \a size modulo \a the \a size \a of * \a a_hshKey may not be zero, since \a a_hshKey is the key value * for the \a hash \a function. If it is, this operation will * increase the array size. * * \param tableSize * The requested array size. If \a tableSize is zero or negative, * this operation will fail. * * \param destroyAction * Pointer to a user defined function for destroying a user defined * data structure. This value will be used in other functions. For * convenience reasons it must be specified here this once. This * value may be NULL. In that case, no user defined function will be * called upon data destroying, only internal hash table memory will * be freed. This way, the key value to the hash table, \a a_hshkey, * is used as the user data itself, instead of a pointer to the data. * * \return * Pointer to the newly created hash table, or NULL if anything * failed, like when there's not enough memory available for the * specified \a tableSize, or when \a tableSize is lower than 1. * * \see * a_hshDestroyAction */ a_hshHashtable a_hshCreateHashtable( c_long tableSize, a_hshDestroyAction destroyAction) { a_hshHashtable hashtable; while (tableSize % sizeof(a_hshKey) == 0) { // force size *not* to be dividable by 4 tableSize++; } if (0 < tableSize) { size_t size = sizeof(struct a_hshHashtable_s) + tableSize * sizeof(struct a_hshBucket_s); hashtable = a_memAlloc(size); if (hashtable) { c_long index; hashtable->tableSize = tableSize; hashtable->destroyAction = destroyAction; hashtable->count = 0; index = tableSize; while (index--) { hashtable->buckets[index] = NULL; } } } else { hashtable = NULL; } return hashtable; }
/* Creates an lstObject and copies data from the lstEntry * into it. Returns a pointer to this new object, or NULL * if the malloc failed. * This copy construction is required for keeping specific * members of lstEntry hidden to the outside, like some * tree members (from a_tre). * Remember to free (using a_memfree()) the object after * use. */ static a_lstObject a_lstEntryToObject( a_lstEntry entry) { a_lstObject o = a_memAlloc(sizeof(struct a_lstObject)); if (o) { o->address = entry->address; o->refCount = entry->refCount; o->alignment = entry->alignment; o->size = entry->size; o->ourSize = entry->ourSize; o->objectName = a_memStrdup(entry->objectName); o->typeName = a_memStrdup(entry->typeName); o->typeDesc = a_memStrdup(entry->typeDesc); o->value = a_memStrdup(entry->value); o->note = a_memStrdup(entry->note); o->occurrencesCount = entry->occurrencesCount; o->typeRefsCount = entry->typeRefsCount; o->dataRefsCount = entry->dataRefsCount; o->unknRefsCount = entry->unknRefsCount; o->refsToTypeCount = entry->refsToTypeCount; o->refsToDataCount = entry->refsToDataCount; o->refsToUnknCount = entry->refsToUnknCount; o->kind = entry->kind; o->refsDifference = o->refCount - (o->typeRefsCount + o->dataRefsCount); o->occurrenceDiff = o->occurrencesCount - o->typeRefsCount - o->dataRefsCount - o->unknRefsCount; } return o; }
/* Creates and initialises a new bucket. Returns NULL if creation * failed (memory full?). */ static a_hshBucket a_hshCreateBucket() { a_hshBucket bucket = a_memAlloc(sizeof(struct a_hshBucket_s)); if (bucket) { bucket->first = NULL; bucket->count = 0; } return bucket; }
static a_apiTimerResults a_apiCreateTimerResults() { a_apiTimerResults timerResults = a_memAlloc(sizeof(struct a_apiTimerResults)); if (timerResults) { timerResults->shmCopyMilSecs = 0; timerResults->shmCopyMicroSecs = 0; timerResults->listFillMilSecs = 0; timerResults->analyseMilSecs = 0; } return timerResults; }
/* Creates and initialises a new Node and returns a pointer to that node. * Returns NULL if anything failed, like memory full. */ static a_hshNode a_hshCreateNode( a_hshKey key, a_hshValue value) { a_hshNode node = a_memAlloc(sizeof(struct a_hshNode_s)); if (node) { node->key = key; node->value = value; node->next = NULL; } return node; }
static a_apiListTotals a_apiCreateListTotals() { a_apiListTotals apiListTotals = a_memAlloc(sizeof(struct a_apiListTotals)); if (apiListTotals) { apiListTotals->objs = 0; apiListTotals->refC = 0; apiListTotals->tRef = 0; apiListTotals->dRef = 0; apiListTotals->uRef = 0; apiListTotals->diff = 0; apiListTotals->occrs = 0; apiListTotals->odiff = 0; } return apiListTotals; }
/* Same functionality as os_strdup, but uses os_malloc internally, * which makes it platform independent */ char * a_memStrdup( char *src) { #if 0 char *target; if (src) { target = a_memAlloc(strlen(src) + 1); strcpy(target, src); } else { target = NULL; } return target; #else return src ? os_strdup(src) : NULL; #endif }
/** * \brief * Creates a new list * * This operation creates a list (on heap) and returns a pointer * to that list. This operation will fail if the memory can not * be allocated. * * \return * Pointer to the newly created list, or NULL if the operation * fails. * * \remark * This operation uses os_malloc() internally, intending to be * platform independent. * * \see * a_lstList a_lstDestroyList */ a_lstList a_lstCreateList( c_long occurrencesArraySize) { a_lstList list = a_memAlloc(sizeof(struct a_lstList_s)); if (list) { c_long i; for (i = 0; i < L_COUNT; i++) { list->counters[i] = 0; } list->tree = a_treCreateTree(); list->occurrencesArraySize = occurrencesArraySize; list->occurrences = NULL; // will be created later list->lastEntry = NULL; } return list; }
/* Part of a_apiPrepare: * Loads (fills) the memory on heap from file. * The actual loading is done in a_fil. */ static int a_apiPrepareLoadFile2Heap( a_apiContext context, char *memFname) { FUNC("a_apiPrepareLoadFile2Heap"); int result = 0; context->filContext = a_filInit(memFname, "", "", (c_address)NULL, 0); HERE("filContext initialised"); result = a_filReadHeader(context->filContext); if (result) { HERE("Header read success"); char *shmName = a_filGetShmName(context->filContext); char *dbName = a_filGetDbName(context->filContext); c_address address = a_filGetShmAddress(context->filContext); long size = a_filGetShmSize(context->filContext); if (shmName) { a_apiSetNewShmName(context, shmName); } if (dbName) { a_apiSetNewDbName(context, dbName); } if (address) { context->address = address; } if (size) { context->size = size; } if ((context->heapMem = (c_address)a_memAlloc(context->size)) != (c_address)NULL) { HERE("malloc success"); result = a_filFile2Heap(context->filContext, context->heapMem); if (result) { HERE("result of a_filFile2Heap: success"); } else { HERE("result of a_filFile2Heap: fail"); } } else { HERE("malloc fail"); result = 0; } } else { HERE("Header read fail"); } return result; }
/** * \brief * Initialises the context for this file * * This operation creates a new context for this file's use and must * be executed before any other operation in this file. Remember to * call the de-init operation after use, and before the application * terminates. * * \param out * Pointer to where output must be redirected to (typically stdout). * This value is used for outputting debug info, verbose output (see * below) and hex dumps. * * \param err * Pointer to where error messages must be redirected to (typically * stderr). This value is used for outputting debug info, verbose * output (see below) and hex dumps. * * \param shm_name * The Shared Memory Name to attach to. * * \param db_name * The Database Name (within the shared memory) to open. * * \param dir * The directory where SPLICE's temporary key files are stored for * the AAPI to parse. Typically "/tmp". * * \param mask * File Mask of SPLICE's temporary key files. Typically "spddskey_". * Do not use wildcards here, AAPI will asume a "*" as a suffix * itself. * * \param showAnalyseOutput * Boolean setting whether to show how all object info is gathered * and processed (debug info). It uses \a out for redirection. * * \param verboseOutput * Boolean setting whether to show some progress info about AAPI's * analyse stage. With databases with more than - say - 5000 objects, * this setting might become useful. * * \return * Pointer to the new context, or NULL if anything failed. * * \see * a_apiDeInit */ a_apiContext a_apiInit( FILE *out, FILE *err, char *shmName, char *dbName, char *dir, char *mask, int showAnalyseOutput, int verboseOutput) { a_apiContext context = a_memAlloc(sizeof(struct a_apiContext_s)); if (context) { context->heapMem = (c_address)NULL; context->out = out; context->err = err; context->showAnalyseOutput = showAnalyseOutput; context->verboseOutput = verboseOutput; context->shmName = a_memStrdup(shmName); context->shmContext = a_shmInit(context->out, context->err, context->shmName); context->address = 0; context->size = 0; context->dbName = a_memStrdup(dbName); context->bseContext = a_bseInit(context->dbName); context->utlContext = a_utlInit(); context->list = a_lstCreateList(A_OCCURRENCES_ARRAY_SIZE); context->stsContext = a_stsInit(); context->anlContext = a_anlInit(context->out, context->err, context->list, context->showAnalyseOutput, context->verboseOutput, context->stsContext); context->keyContext = a_keyInit(dir, mask); context->filContext = (c_address)NULL; context->listTotals = a_apiCreateListTotals(); context->timerResults = a_apiCreateTimerResults(); context->error = A_ERR_OK; } return context; }
a_filContext a_filInit( char *fname, char *shm_name, char *db_name, c_address address, c_long shm_size) { a_filContext context = a_memAlloc(sizeof(struct a_filContext_s)); context->fname = fname ? a_memStrdup(fname) : NULL; if (shm_name) { strcpy(context->memFileMeta.shm_name, shm_name); } if (db_name) { strcpy(context->memFileMeta.db_name, db_name); } context->memFileMeta.address = address; context->memFileMeta.shm_size = shm_size; return context; }
/* Creates a new entry and returns a pointer to that entry */ static a_lstEntry a_lstNewEntry( c_address address, c_long refCount, a_lstObjectKind kind, char *objectName, char *typeDesc, char *typeName, c_long alignment, c_long size) { a_lstEntry entry = a_memAlloc(sizeof(struct a_lstEntry)); if (entry) { entry->address = address; entry->refCount = refCount; entry->kind = kind; entry->objectName = a_memStrdup(objectName); entry->typeDesc = a_memStrdup(typeDesc); entry->typeName = a_memStrdup(typeName); entry->alignment = alignment; entry->size = size; entry->ourSize = size; // initially entry->value = NULL; entry->note = NULL; entry->occurrencesCount = 0; entry->typeRefsCount = 0; entry->dataRefsCount = 0; entry->unknRefsCount = 0; entry->refsToTypeCount = 0; entry->refsToDataCount = 0; entry->refsToUnknCount = 0; entry->occurrences = NULL; // subtree('s) will be created entry->typeRefs = NULL; // at first insertion! entry->dataRefs = NULL; entry->unknRefs = NULL; entry->refsToType = NULL; entry->refsToData = NULL; entry->refsToUnkn = NULL; } return entry; }
/** * \brief * Calls a user defined call back function to "push" some statistics * about the database. * * This operation calls a user defined function, of that of an * \a a_apiInfoDataAction type, to pass back an instance of * \a a_apiInfoData. Upon returning from the user defined function, * this instance will be destroyed. * * \param context * This file's context. It must have been created by \a a_apiInit. If * context is NULL, this operation will fail. * * \param action * Pointer to a user defined function that will be called. If * \a action is NULL, this operation will fail. * * \param actionArg * Pointer to a user defined context that will be passed along with * the call to the user defined function. May be NULL. * * \return * Boolean value specifying this operation's success (1) or failure * (0). If the user defined function returns 0, this function will * return 0 as well. * * \see * a_apiInfoDataAction a_apiInfoData */ int a_apiPushMeInfoData( a_apiContext context, a_apiInfoDataAction action, void *actionArg) { int result; if (context) { a_apiInfoData infoData = a_memAlloc(sizeof(struct a_apiInfoData_s)); if (infoData) { infoData->shmName = a_memStrdup(a_shmGetShmName(context->shmContext)); infoData->dbName = a_memStrdup(a_bseGetBaseName(context->bseContext)); infoData->shmAddress = (long)a_shmGetShmAddress(context->shmContext); infoData->shmSize = 0; infoData->bseAddress = (long)a_bseGetBaseAddr(context->bseContext); infoData->mmSize = a_bseGetStateProperty(context->bseContext, A_BSE_STATE_SIZE); infoData->mmUsed = a_bseGetStateProperty(context->bseContext, A_BSE_STATE_USED); infoData->mmMaxUsed = a_bseGetStateProperty(context->bseContext, A_BSE_STATE_MAXUSED); infoData->mmFails = a_bseGetStateProperty(context->bseContext, A_BSE_STATE_FAILS); infoData->mmGarbage = a_bseGetStateProperty(context->bseContext, A_BSE_STATE_GARBAGE); infoData->mmCount = a_bseGetStateProperty(context->bseContext, A_BSE_STATE_COUNT); infoData->clssObjs = a_lstCount(context->list, L_CLSS); infoData->baseObjs = a_lstCount(context->list, L_BASE); infoData->metaObjs = a_lstCount(context->list, L_META); infoData->dataObjs = a_lstCount(context->list, L_DATA); infoData->undfObjs = a_lstCount(context->list, L_UNDF); infoData->dataSize = a_anlTotalDataSize(context->anlContext); result = (action)(infoData, actionArg); a_memFree(infoData->shmName); a_memFree(infoData->dbName); a_memFree(infoData); } else { result = 0; } } else { result = 0; } return result; }
/* Part of a_apiPrepare: * Copies Shared Memory to Heap */ static int a_apiPrepareCopyShm2Heap( a_apiContext context) { FUNC("a_apiPrepareCopyShm2Heap"); /* Use origShmContext for attaching the original shm: */ a_shmContext origShmContext; context->error = A_ERR_OK; origShmContext = a_shmInit(context->out, context->err, context->shmName); if ( a_shmAttach(origShmContext) ) { HERE("attached"); // shm is attached, now determine start address: context->address = a_shmGetShmAddress(origShmContext); HERE("startAddress acquired"); assert(context->address); if ( a_bseOpenBase(context->bseContext, context->address) ) { HERE("base opened"); context->size = (long)a_keyGetSize(context->keyContext, context->shmName); // printf("size: %ld (0x%X)\n", context->size, (unsigned int)context->size); HERE("size acquired, going to copy shm mem to heap:"); //printf("[a_apiPrepare] address = 0x%X, size = %ld (0x%X)\n", // (unsigned int)context->address, context->size, (unsigned int)context->size); // copy shm to heap: assert(context->size); if ((context->heapMem = (c_address)a_memAlloc(context->size)) != (c_address)NULL){ HERE("malloc succesful"); int cpyMemResult; a_utlStopWatchStart(context->utlContext); cpyMemResult = a_memCopyMem((void *)context->heapMem, (void *)context->address, context->size); a_utlStopWatchStop(context->utlContext); context->timerResults->shmCopyMicroSecs = a_utlGetStopWatchTimeMicroSecs(context->utlContext); context->timerResults->shmCopyMilSecs = a_utlGetStopWatchTimeMilSecs(context->utlContext); if (cpyMemResult) { HERE("mem cloned on heap"); // detach (original) shm if ( a_shmDetach(origShmContext) ) { HERE("original shm detached"); //printf("[a_apiPrepare] startAddress = 0x%X, size = 0x%X (%ld)\n", // (unsigned int)startAddress, (unsigned int)size, size); } else { context->error = A_ERR_SHM_DETACH_FAIL; HERE("?could not detach original shm"); } } else { context->error = A_ERR_MEMCOPY_FAIL; HERE("?copy from heap to shm failed"); } } else { HERE("?malloc failed"); context->error = A_ERR_MALLOC_FAIL; } } else { context->error = A_ERR_BASE_OPEN_FAIL; HERE("?base not opened"); } a_shmDeInit(origShmContext); HERE("original shm deinitialised"); } else { HERE("?could not attach to original shm"); context->error = A_ERR_SHM_ATTACH_FAIL; } return (context->error == A_ERR_OK) ? 1 : 0; }