Initial import of edited debug reader
This commit is contained in:
		
							
								
								
									
										498
									
								
								amxmodx/amxdbg.cpp
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										498
									
								
								amxmodx/amxdbg.cpp
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,498 @@ | |||||||
|  | /*  Pawn debugger interface | ||||||
|  |  * | ||||||
|  |  *  Support functions for debugger applications | ||||||
|  |  * | ||||||
|  |  *  Copyright (c) ITB CompuPhase, 2005 | ||||||
|  |  * | ||||||
|  |  *  This software is provided "as-is", without any express or implied warranty. | ||||||
|  |  *  In no event will the authors be held liable for any damages arising from | ||||||
|  |  *  the use of this software. | ||||||
|  |  * | ||||||
|  |  *  Permission is granted to anyone to use this software for any purpose, | ||||||
|  |  *  including commercial applications, and to alter it and redistribute it | ||||||
|  |  *  freely, subject to the following restrictions: | ||||||
|  |  * | ||||||
|  |  *  1.  The origin of this software must not be misrepresented; you must not | ||||||
|  |  *      claim that you wrote the original software. If you use this software in | ||||||
|  |  *      a product, an acknowledgment in the product documentation would be | ||||||
|  |  *      appreciated but is not required. | ||||||
|  |  *  2.  Altered source versions must be plainly marked as such, and must not be | ||||||
|  |  *      misrepresented as being the original software. | ||||||
|  |  *  3.  This notice may not be removed or altered from any source distribution. | ||||||
|  |  * | ||||||
|  |  *  Version: $Id$ | ||||||
|  |  */ | ||||||
|  | #include <assert.h> | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <string.h> | ||||||
|  | #include <stdarg.h> | ||||||
|  | #include "osdefs.h"     /* for _MAX_PATH */ | ||||||
|  | #include "amx.h" | ||||||
|  | #include "amxdbg.h" | ||||||
|  |  | ||||||
|  | // this file does not include amxmodx.h, so we have to include the memory manager here | ||||||
|  | #ifdef MEMORY_TEST | ||||||
|  | #include "mmgr/mmgr.h" | ||||||
|  | #endif // MEMORY_TEST | ||||||
|  |  | ||||||
|  | int AMXAPI dbg_FreeInfo(AMX_DBG *amxdbg) | ||||||
|  | { | ||||||
|  |   assert(amxdbg != NULL); | ||||||
|  |   if (amxdbg->hdr != NULL) | ||||||
|  |     free(amxdbg->hdr); | ||||||
|  |   if (amxdbg->filetbl != NULL) | ||||||
|  |     free(amxdbg->filetbl); | ||||||
|  |   if (amxdbg->symboltbl != NULL) | ||||||
|  |     free(amxdbg->symboltbl); | ||||||
|  |   if (amxdbg->tagtbl != NULL) | ||||||
|  |     free(amxdbg->tagtbl); | ||||||
|  |   if (amxdbg->automatontbl != NULL) | ||||||
|  |     free(amxdbg->automatontbl); | ||||||
|  |   if (amxdbg->statetbl != NULL) | ||||||
|  |     free(amxdbg->statetbl); | ||||||
|  |   memset(amxdbg, 0, sizeof(AMX_DBG)); | ||||||
|  |   return AMX_ERR_NONE; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void memread(void *dest, char **src, size_t size) | ||||||
|  | { | ||||||
|  | 	void *ptr = *src; | ||||||
|  | 	memcpy(dest, ptr, size); | ||||||
|  | 	*src += size; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const char *ClipFileName(const char *inp) | ||||||
|  | { | ||||||
|  | 	static char buffer[256]; | ||||||
|  | 	size_t len = strlen(inp); | ||||||
|  | 	const char *ptr = inp; | ||||||
|  |  | ||||||
|  | 	for (size_t i=0; i<len; i++) | ||||||
|  | 	{ | ||||||
|  | 		if ((inp[i] == '\\' || inp[i] == '/') && (i != len-1)) | ||||||
|  | 			ptr = inp + i + 1; | ||||||
|  | 	} | ||||||
|  | 	strcpy(buffer, ptr); | ||||||
|  |  | ||||||
|  | 	return buffer; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //Note - I changed this function to read from memory instead. | ||||||
|  | // -- BAILOPAN | ||||||
|  | int AMXAPI dbg_LoadInfo(AMX_DBG *amxdbg, void *dbg_addr) | ||||||
|  | { | ||||||
|  |   AMX_DBG_HDR dbghdr; | ||||||
|  |   unsigned char *ptr; | ||||||
|  |   int index, dim; | ||||||
|  |   AMX_DBG_SYMDIM *symdim; | ||||||
|  |  | ||||||
|  |   assert(amxdbg != NULL); | ||||||
|  |  | ||||||
|  |   char *addr = (char *)(dbg_addr); | ||||||
|  |  | ||||||
|  |   memset(&dbghdr, 0, sizeof(AMX_DBG_HDR)); | ||||||
|  |   memread(&dbghdr, &addr, sizeof(AMX_DBG_HDR)); | ||||||
|  |  | ||||||
|  |   //brabbby graa gragghty graaahhhh | ||||||
|  |   #if BYTE_ORDER==BIG_ENDIAN | ||||||
|  |     amx_Align32((uint32_t*)&dbghdr.size); | ||||||
|  |     amx_Align16(&dbghdr.magic); | ||||||
|  |     amx_Align16(&dbghdr.flags); | ||||||
|  |     amx_Align16(&dbghdr.files); | ||||||
|  |     amx_Align16(&dbghdr.lines); | ||||||
|  |     amx_Align16(&dbghdr.symbols); | ||||||
|  |     amx_Align16(&dbghdr.tags); | ||||||
|  |     amx_Align16(&dbghdr.automatons); | ||||||
|  |     amx_Align16(&dbghdr.states); | ||||||
|  |   #endif | ||||||
|  |  | ||||||
|  |   if (dbghdr.magic != AMX_DBG_MAGIC) | ||||||
|  |     return AMX_ERR_FORMAT; | ||||||
|  |  | ||||||
|  |   /* allocate all memory */ | ||||||
|  |   memset(amxdbg, 0, sizeof(AMX_DBG)); | ||||||
|  |   amxdbg->hdr = (AMX_DBG_HDR *)malloc((size_t)dbghdr.size); | ||||||
|  |   if (dbghdr.files > 0) | ||||||
|  |     amxdbg->filetbl = (AMX_DBG_FILE **)malloc(dbghdr.files * sizeof(AMX_DBG_FILE *)); | ||||||
|  |   if (dbghdr.symbols > 0) | ||||||
|  |     amxdbg->symboltbl = (AMX_DBG_SYMBOL **)malloc(dbghdr.symbols * sizeof(AMX_DBG_SYMBOL *)); | ||||||
|  |   if (dbghdr.tags > 0) | ||||||
|  |     amxdbg->tagtbl = (AMX_DBG_TAG **)malloc(dbghdr.tags * sizeof(AMX_DBG_TAG *)); | ||||||
|  |   if (dbghdr.automatons > 0) | ||||||
|  |     amxdbg->automatontbl = (AMX_DBG_MACHINE **)malloc(dbghdr.automatons * sizeof(AMX_DBG_MACHINE *)); | ||||||
|  |   if (dbghdr.states > 0) | ||||||
|  |     amxdbg->statetbl = (AMX_DBG_STATE **)malloc(dbghdr.states * sizeof(AMX_DBG_STATE *)); | ||||||
|  |   if (amxdbg->hdr == NULL | ||||||
|  |       || (dbghdr.files > 0 && amxdbg->filetbl == NULL) | ||||||
|  |       || (dbghdr.symbols > 0 && amxdbg->symboltbl == NULL) | ||||||
|  |       || (dbghdr.tags > 0 && amxdbg->tagtbl == NULL) | ||||||
|  |       || (dbghdr.states > 0 && amxdbg->statetbl == NULL) | ||||||
|  |       || (dbghdr.automatons > 0 && amxdbg->automatontbl == NULL)) | ||||||
|  |   { | ||||||
|  |     dbg_FreeInfo(amxdbg); | ||||||
|  |     return AMX_ERR_MEMORY; | ||||||
|  |   } /* if */ | ||||||
|  |  | ||||||
|  |   /* load the entire symbolic information block into memory */ | ||||||
|  |   memcpy(amxdbg->hdr, &dbghdr, sizeof dbghdr); | ||||||
|  |   ptr = (unsigned char *)(amxdbg->hdr + 1); | ||||||
|  |   memread(ptr, &addr, (size_t)(dbghdr.size-sizeof(dbghdr))); | ||||||
|  |  | ||||||
|  |   /* file table */ | ||||||
|  |   for (index = 0; index < dbghdr.files; index++) { | ||||||
|  |     assert(amxdbg->filetbl != NULL); | ||||||
|  |     amxdbg->filetbl[index] = (AMX_DBG_FILE *)ptr; | ||||||
|  |     #if BYTE_ORDER==BIG_ENDIAN | ||||||
|  |       amx_AlignCell(&amxdbg->filetbl[index]->address); | ||||||
|  |     #endif | ||||||
|  |     for (ptr = ptr + sizeof(AMX_DBG_FILE); *ptr != '\0'; ptr++) | ||||||
|  |       /* nothing */; | ||||||
|  |     ptr++;              /* skip '\0' too */ | ||||||
|  |   } /* for */ | ||||||
|  |  | ||||||
|  |   //debug("Files: %d\n", amxdbg->hdr->files); | ||||||
|  |   for (index=0;index<amxdbg->hdr->files; index++) | ||||||
|  |   { | ||||||
|  | 	  strcpy((char *)amxdbg->filetbl[index]->name, ClipFileName(amxdbg->filetbl[index]->name)); | ||||||
|  | 	  //debug(" [%d] %s\n", index, amxdbg->filetbl[index]->name); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /* line table */ | ||||||
|  |   amxdbg->linetbl = (AMX_DBG_LINE*)ptr; | ||||||
|  |   #if BYTE_ORDER==BIG_ENDIAN | ||||||
|  |     for (index = 0; index < dbghdr.lines; index++) { | ||||||
|  |       amx_AlignCell(&amxdbg->linetbl[index].address); | ||||||
|  |       amx_Align32((uint32_t*)&amxdbg->linetbl[index].line); | ||||||
|  |     } /* for */ | ||||||
|  |   #endif | ||||||
|  |   ptr += dbghdr.lines * sizeof(AMX_DBG_LINE); | ||||||
|  |  | ||||||
|  |   /* symbol table (plus index tags) */ | ||||||
|  |   for (index = 0; index < dbghdr.symbols; index++) { | ||||||
|  |     assert(amxdbg->symboltbl != NULL); | ||||||
|  |     amxdbg->symboltbl[index] = (AMX_DBG_SYMBOL *)ptr; | ||||||
|  |     #if BYTE_ORDER==BIG_ENDIAN | ||||||
|  |       amx_AlignCell(&amxdbg->symboltbl[index]->address); | ||||||
|  |       amx_Align16((uint16_t*)&amxdbg->symboltbl[index]->tag); | ||||||
|  |       amx_AlignCell(&amxdbg->symboltbl[index]->codestart); | ||||||
|  |       amx_AlignCell(&amxdbg->symboltbl[index]->codeend); | ||||||
|  |       amx_Align16((uint16_t*)&amxdbg->symboltbl[index]->dim); | ||||||
|  |     #endif | ||||||
|  |     for (ptr = ptr + sizeof(AMX_DBG_SYMBOL); *ptr != '\0'; ptr++) | ||||||
|  |       /* nothing */; | ||||||
|  |     ptr++;              /* skip '\0' too */ | ||||||
|  |     for (dim = 0; dim < amxdbg->symboltbl[index]->dim; dim++) { | ||||||
|  |       symdim = (AMX_DBG_SYMDIM *)ptr; | ||||||
|  |       amx_Align16((uint16_t*)&symdim->tag); | ||||||
|  |       amx_AlignCell(&symdim->size); | ||||||
|  |       ptr += sizeof(AMX_DBG_SYMDIM); | ||||||
|  |     } /* for */ | ||||||
|  |   } /* for */ | ||||||
|  |  | ||||||
|  |   /* tag name table */ | ||||||
|  |   for (index = 0; index < dbghdr.tags; index++) { | ||||||
|  |     assert(amxdbg->tagtbl != NULL); | ||||||
|  |     amxdbg->tagtbl[index] = (AMX_DBG_TAG *)ptr; | ||||||
|  |     #if BYTE_ORDER==BIG_ENDIAN | ||||||
|  |       amx_Align16(&amxdbg->tagtbl[index]->tag); | ||||||
|  |     #endif | ||||||
|  |     for (ptr = ptr + sizeof(AMX_DBG_TAG) - 1; *ptr != '\0'; ptr++) | ||||||
|  |       /* nothing */; | ||||||
|  |     ptr++;              /* skip '\0' too */ | ||||||
|  |   } /* for */ | ||||||
|  |  | ||||||
|  |   /* automaton name table */ | ||||||
|  |   for (index = 0; index < dbghdr.automatons; index++) { | ||||||
|  |     assert(amxdbg->automatontbl != NULL); | ||||||
|  |     amxdbg->automatontbl[index] = (AMX_DBG_MACHINE *)ptr; | ||||||
|  |     #if BYTE_ORDER==BIG_ENDIAN | ||||||
|  |       amx_Align16(&amxdbg->automatontbl[index]->automaton); | ||||||
|  |       amx_AlignCell(&amxdbg->automatontbl[index]->address); | ||||||
|  |     #endif | ||||||
|  |     for (ptr = ptr + sizeof(AMX_DBG_MACHINE) - 1; *ptr != '\0'; ptr++) | ||||||
|  |       /* nothing */; | ||||||
|  |     ptr++;              /* skip '\0' too */ | ||||||
|  |   } /* for */ | ||||||
|  |  | ||||||
|  |   /* state name table */ | ||||||
|  |   for (index = 0; index < dbghdr.states; index++) { | ||||||
|  |     assert(amxdbg->statetbl != NULL); | ||||||
|  |     amxdbg->statetbl[index] = (AMX_DBG_STATE *)ptr; | ||||||
|  |     #if BYTE_ORDER==BIG_ENDIAN | ||||||
|  |       amx_Align16(&amxdbg->statetbl[index]->state); | ||||||
|  |       amx_Align16(&amxdbg->automatontbl[index]->automaton); | ||||||
|  |     #endif | ||||||
|  |     for (ptr = ptr + sizeof(AMX_DBG_STATE) - 1; *ptr != '\0'; ptr++) | ||||||
|  |       /* nothing */; | ||||||
|  |     ptr++;              /* skip '\0' too */ | ||||||
|  |   } /* for */ | ||||||
|  |  | ||||||
|  |   return AMX_ERR_NONE; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int AMXAPI dbg_LookupFile(AMX_DBG *amxdbg, ucell address, const char **filename) | ||||||
|  | { | ||||||
|  |   int index; | ||||||
|  |  | ||||||
|  |   assert(amxdbg != NULL); | ||||||
|  |   assert(filename != NULL); | ||||||
|  |   *filename = NULL; | ||||||
|  |   /* this is a simple linear look-up; a binary search would be possible too */ | ||||||
|  |   for (index = 0; index < amxdbg->hdr->files && amxdbg->filetbl[index]->address <= address; index++) | ||||||
|  |     /* nothing */; | ||||||
|  |   /* reset for overrun */ | ||||||
|  |   if (--index < 0) | ||||||
|  |     return AMX_ERR_NOTFOUND; | ||||||
|  |  | ||||||
|  |   *filename = amxdbg->filetbl[index]->name; | ||||||
|  |   return AMX_ERR_NONE; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int AMXAPI dbg_LookupLine(AMX_DBG *amxdbg, ucell address, long *line) | ||||||
|  | { | ||||||
|  |   int index; | ||||||
|  |  | ||||||
|  |   assert(amxdbg != NULL); | ||||||
|  |   assert(line != NULL); | ||||||
|  |   *line = 0; | ||||||
|  |   /* this is a simple linear look-up; a binary search would be possible too */ | ||||||
|  |   for (index = 0; index < amxdbg->hdr->lines && amxdbg->linetbl[index].address <= address; index++) | ||||||
|  |     /* nothing */; | ||||||
|  |   /* reset for overrun */ | ||||||
|  |   if (--index < 0) | ||||||
|  |     return AMX_ERR_NOTFOUND; | ||||||
|  |  | ||||||
|  |   *line = (long)amxdbg->linetbl[index].line; | ||||||
|  |   return AMX_ERR_NONE; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int AMXAPI dbg_LookupFunction(AMX_DBG *amxdbg, ucell address, const char **funcname) | ||||||
|  | { | ||||||
|  |   /* dbg_LookupFunction() finds the function a code address is in. It can be | ||||||
|  |    * used for stack walking, and for stepping through a function while stepping | ||||||
|  |    * over sub-functions | ||||||
|  |    */ | ||||||
|  |   int index; | ||||||
|  |  | ||||||
|  |   assert(amxdbg != NULL); | ||||||
|  |   assert(funcname != NULL); | ||||||
|  |   *funcname = NULL; | ||||||
|  |   for (index = 0; index < amxdbg->hdr->symbols; index++) { | ||||||
|  |     if (amxdbg->symboltbl[index]->ident == iFUNCTN | ||||||
|  |         && amxdbg->symboltbl[index]->codestart <= address | ||||||
|  |         && amxdbg->symboltbl[index]->codeend > address) | ||||||
|  |       break; | ||||||
|  |   } /* for */ | ||||||
|  |   if (index >= amxdbg->hdr->symbols) | ||||||
|  |     return AMX_ERR_NOTFOUND; | ||||||
|  |  | ||||||
|  |   *funcname = amxdbg->symboltbl[index]->name; | ||||||
|  |   return AMX_ERR_NONE; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int AMXAPI dbg_GetTagName(AMX_DBG *amxdbg, int tag, const char **name) | ||||||
|  | { | ||||||
|  |   int index; | ||||||
|  |  | ||||||
|  |   assert(amxdbg != NULL); | ||||||
|  |   assert(name != NULL); | ||||||
|  |   *name = NULL; | ||||||
|  |   for (index = 0; index < amxdbg->hdr->tags && amxdbg->tagtbl[index]->tag != tag; index++) | ||||||
|  |     /* nothing */; | ||||||
|  |   if (index >= amxdbg->hdr->tags) | ||||||
|  |     return AMX_ERR_NOTFOUND; | ||||||
|  |  | ||||||
|  |   *name = amxdbg->tagtbl[index]->name; | ||||||
|  |   return AMX_ERR_NONE; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int AMXAPI dbg_GetAutomatonName(AMX_DBG *amxdbg, int automaton, const char **name) | ||||||
|  | { | ||||||
|  |   int index; | ||||||
|  |  | ||||||
|  |   assert(amxdbg != NULL); | ||||||
|  |   assert(name != NULL); | ||||||
|  |   *name = NULL; | ||||||
|  |   for (index = 0; index < amxdbg->hdr->automatons && amxdbg->automatontbl[index]->automaton != automaton; index++) | ||||||
|  |     /* nothing */; | ||||||
|  |   if (index >= amxdbg->hdr->automatons) | ||||||
|  |     return AMX_ERR_NOTFOUND; | ||||||
|  |  | ||||||
|  |   *name = amxdbg->automatontbl[index]->name; | ||||||
|  |   return AMX_ERR_NONE; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int AMXAPI dbg_GetStateName(AMX_DBG *amxdbg, int state, const char **name) | ||||||
|  | { | ||||||
|  |   int index; | ||||||
|  |  | ||||||
|  |   assert(amxdbg != NULL); | ||||||
|  |   assert(name != NULL); | ||||||
|  |   *name = NULL; | ||||||
|  |   for (index = 0; index < amxdbg->hdr->states && amxdbg->statetbl[index]->state != state; index++) | ||||||
|  |     /* nothing */; | ||||||
|  |   if (index >= amxdbg->hdr->states) | ||||||
|  |     return AMX_ERR_NOTFOUND; | ||||||
|  |  | ||||||
|  |   *name = amxdbg->statetbl[index]->name; | ||||||
|  |   return AMX_ERR_NONE; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int AMXAPI dbg_GetLineAddress(AMX_DBG *amxdbg, long line, const char *filename, ucell *address) | ||||||
|  | { | ||||||
|  |   /* Find a suitable "breakpoint address" close to the indicated line (and in | ||||||
|  |    * the specified file). The address is moved up to the next "breakable" line | ||||||
|  |    * if no "breakpoint" is available on the specified line. You can use function | ||||||
|  |    * dbg_LookupLine() to find out at which precise line the breakpoint was set. | ||||||
|  |    * | ||||||
|  |    * The filename comparison is strict (case sensitive and path sensitive); the | ||||||
|  |    * "filename" parameter should point into the "filetbl" of the AMX_DBG | ||||||
|  |    * structure. | ||||||
|  |    */ | ||||||
|  |   int file, index; | ||||||
|  |   ucell bottomaddr,topaddr; | ||||||
|  |  | ||||||
|  |   assert(amxdbg != NULL); | ||||||
|  |   assert(filename != NULL); | ||||||
|  |   assert(address != NULL); | ||||||
|  |   *address = 0; | ||||||
|  |  | ||||||
|  |   index = 0; | ||||||
|  |   for (file = 0; file < amxdbg->hdr->files; file++) { | ||||||
|  |     /* find the (next) mathing instance of the file */ | ||||||
|  |     if (strcmp(amxdbg->filetbl[file]->name, filename) != 0) | ||||||
|  |       continue; | ||||||
|  |     /* get address range for the current file */ | ||||||
|  |     bottomaddr = amxdbg->filetbl[file]->address; | ||||||
|  |     topaddr = (file + 1 < amxdbg->hdr->files) ? amxdbg->filetbl[file+1]->address : (ucell)(cell)-1; | ||||||
|  |     /* go to the starting address in the line table */ | ||||||
|  |     while (index < amxdbg->hdr->lines && amxdbg->linetbl[index].address < bottomaddr) | ||||||
|  |       index++; | ||||||
|  |     /* browse until the line is found or until the top address is exceeded */ | ||||||
|  |     while (index < amxdbg->hdr->lines | ||||||
|  |            && amxdbg->linetbl[index].line < line | ||||||
|  |            && amxdbg->linetbl[index].address < topaddr) | ||||||
|  |       index++; | ||||||
|  |     if (index >= amxdbg->hdr->lines) | ||||||
|  |       return AMX_ERR_NOTFOUND; | ||||||
|  |     if (amxdbg->linetbl[index].line >= line) | ||||||
|  |       break; | ||||||
|  |     /* if not found (and the line table is not yet exceeded) try the next | ||||||
|  |      * instance of the same file (a file may appear twice in the file table) | ||||||
|  |      */ | ||||||
|  |   } /* for */ | ||||||
|  |  | ||||||
|  |   if (strcmp(amxdbg->filetbl[file]->name, filename) != 0) | ||||||
|  |     return AMX_ERR_NOTFOUND; | ||||||
|  |  | ||||||
|  |   assert(index < amxdbg->hdr->lines); | ||||||
|  |   *address = amxdbg->linetbl[index].address; | ||||||
|  |   return AMX_ERR_NONE; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int AMXAPI dbg_GetFunctionAddress(AMX_DBG *amxdbg, const char *funcname, const char *filename, ucell *address) | ||||||
|  | { | ||||||
|  |   /* Find a suitable "breakpoint address" close to the indicated line (and in | ||||||
|  |    * the specified file). The address is moved up to the first "breakable" line | ||||||
|  |    * in the function. You can use function dbg_LookupLine() to find out at which | ||||||
|  |    * precise line the breakpoint was set. | ||||||
|  |    * | ||||||
|  |    * The filename comparison is strict (case sensitive and path sensitive); the | ||||||
|  |    * "filename" parameter should point into the "filetbl" of the AMX_DBG | ||||||
|  |    * structure. The function name comparison is case sensitive too. | ||||||
|  |    */ | ||||||
|  |   int index, err; | ||||||
|  |   const char *tgtfile; | ||||||
|  |   ucell funcaddr; | ||||||
|  |  | ||||||
|  |   assert(amxdbg != NULL); | ||||||
|  |   assert(funcname != NULL); | ||||||
|  |   assert(filename != NULL); | ||||||
|  |   assert(address != NULL); | ||||||
|  |   *address = 0; | ||||||
|  |  | ||||||
|  |   index = 0; | ||||||
|  |   for ( ;; ) { | ||||||
|  |     /* find (next) matching function */ | ||||||
|  |     while (index < amxdbg->hdr->symbols | ||||||
|  |            && (amxdbg->symboltbl[index]->ident != iFUNCTN || strcmp(amxdbg->symboltbl[index]->name, funcname) != 0)) | ||||||
|  |       index++; | ||||||
|  |     if (index >= amxdbg->hdr->symbols) | ||||||
|  |       return AMX_ERR_NOTFOUND; | ||||||
|  |     /* verify that this line falls in the appropriate file */ | ||||||
|  |     err = dbg_LookupFile(amxdbg, amxdbg->symboltbl[index]->address, &tgtfile); | ||||||
|  |     if (err == AMX_ERR_NONE || strcmp(filename, tgtfile) == 0) | ||||||
|  |       break; | ||||||
|  |     index++;            /* line is the wrong file, search further */ | ||||||
|  |   } /* for */ | ||||||
|  |  | ||||||
|  |   /* now find the first line in the function where we can "break" on */ | ||||||
|  |   assert(index < amxdbg->hdr->symbols); | ||||||
|  |   funcaddr = amxdbg->symboltbl[index]->address; | ||||||
|  |   for (index = 0; index < amxdbg->hdr->lines && amxdbg->linetbl[index].address < funcaddr; index++) | ||||||
|  |     /* nothing */; | ||||||
|  |  | ||||||
|  |   if (index >= amxdbg->hdr->lines) | ||||||
|  |     return AMX_ERR_NOTFOUND; | ||||||
|  |   *address = amxdbg->linetbl[index].address; | ||||||
|  |  | ||||||
|  |   return AMX_ERR_NONE; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int AMXAPI dbg_GetVariable(AMX_DBG *amxdbg, const char *symname, ucell scopeaddr, const AMX_DBG_SYMBOL **sym) | ||||||
|  | { | ||||||
|  |   ucell codestart,codeend; | ||||||
|  |   int index; | ||||||
|  |  | ||||||
|  |   assert(amxdbg != NULL); | ||||||
|  |   assert(symname != NULL); | ||||||
|  |   assert(sym != NULL); | ||||||
|  |   *sym = NULL; | ||||||
|  |  | ||||||
|  |   codestart = codeend = 0; | ||||||
|  |   index = 0; | ||||||
|  |   for ( ;; ) { | ||||||
|  |     /* find (next) matching variable */ | ||||||
|  |     while (index < amxdbg->hdr->symbols | ||||||
|  |            && (amxdbg->symboltbl[index]->ident == iFUNCTN || strcmp(amxdbg->symboltbl[index]->name, symname) != 0) | ||||||
|  |            && (amxdbg->symboltbl[index]->codestart > scopeaddr || amxdbg->symboltbl[index]->codeend < scopeaddr)) | ||||||
|  |       index++; | ||||||
|  |     if (index >= amxdbg->hdr->symbols) | ||||||
|  |       break; | ||||||
|  |     /* check the range, keep a pointer to the symbol with the smallest range */ | ||||||
|  |     if (strcmp(amxdbg->symboltbl[index]->name, symname) == 0 | ||||||
|  |         && (codestart == 0 && codeend == 0 | ||||||
|  |             || amxdbg->symboltbl[index]->codestart >= codestart && amxdbg->symboltbl[index]->codeend <= codeend)) | ||||||
|  |     { | ||||||
|  |       *sym = amxdbg->symboltbl[index]; | ||||||
|  |       codestart = amxdbg->symboltbl[index]->codestart; | ||||||
|  |       codeend = amxdbg->symboltbl[index]->codeend; | ||||||
|  |     } /* if */ | ||||||
|  |     index++; | ||||||
|  |   } /* for */ | ||||||
|  |  | ||||||
|  |   return (*sym == NULL) ? AMX_ERR_NOTFOUND : AMX_ERR_NONE; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int AMXAPI dbg_GetArrayDim(AMX_DBG *amxdbg, const AMX_DBG_SYMBOL *sym, const AMX_DBG_SYMDIM **symdim) | ||||||
|  | { | ||||||
|  |   /* retrieves a pointer to the array dimensions structures of an array symbol */ | ||||||
|  |   const char *ptr; | ||||||
|  |  | ||||||
|  |   assert(amxdbg != NULL); | ||||||
|  |   assert(sym != NULL); | ||||||
|  |   assert(symdim != NULL); | ||||||
|  |   *symdim = NULL; | ||||||
|  |  | ||||||
|  |   if (sym->ident != iARRAY && sym->ident != iREFARRAY) | ||||||
|  |     return AMX_ERR_PARAMS; | ||||||
|  |   assert(sym->dim > 0); /* array must have at least one dimension */ | ||||||
|  |  | ||||||
|  |   /* find the end of the symbol name */ | ||||||
|  |   for (ptr = sym->name; *ptr != '\0'; ptr++) | ||||||
|  |     /* nothing */; | ||||||
|  |   *symdim = (AMX_DBG_SYMDIM *)(ptr + 1);/* skip '\0' too */ | ||||||
|  |  | ||||||
|  |   return AMX_ERR_NONE; | ||||||
|  | } | ||||||
							
								
								
									
										172
									
								
								amxmodx/amxdbg.h
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										172
									
								
								amxmodx/amxdbg.h
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,172 @@ | |||||||
|  | /*  Abstract Machine for the Pawn compiler, debugger support | ||||||
|  |  * | ||||||
|  |  *  This file contains extra definitions that are convenient for debugger | ||||||
|  |  *  support. | ||||||
|  |  * | ||||||
|  |  *  Copyright (c) ITB CompuPhase, 2005 | ||||||
|  |  * | ||||||
|  |  *  This software is provided "as-is", without any express or implied warranty. | ||||||
|  |  *  In no event will the authors be held liable for any damages arising from | ||||||
|  |  *  the use of this software. | ||||||
|  |  * | ||||||
|  |  *  Permission is granted to anyone to use this software for any purpose, | ||||||
|  |  *  including commercial applications, and to alter it and redistribute it | ||||||
|  |  *  freely, subject to the following restrictions: | ||||||
|  |  * | ||||||
|  |  *  1.  The origin of this software must not be misrepresented; you must not | ||||||
|  |  *      claim that you wrote the original software. If you use this software in | ||||||
|  |  *      a product, an acknowledgment in the product documentation would be | ||||||
|  |  *      appreciated but is not required. | ||||||
|  |  *  2.  Altered source versions must be plainly marked as such, and must not be | ||||||
|  |  *      misrepresented as being the original software. | ||||||
|  |  *  3.  This notice may not be removed or altered from any source distribution. | ||||||
|  |  * | ||||||
|  |  *  Version: $Id$ | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #ifndef AMXDBG_H_INCLUDED | ||||||
|  | #define AMXDBG_H_INCLUDED | ||||||
|  |  | ||||||
|  | #ifndef AMX_H_INCLUDED | ||||||
|  |   #include "amx.h" | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #ifdef  __cplusplus | ||||||
|  | extern  "C" { | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | /* Some compilers do not support the #pragma align, which should be fine. Some | ||||||
|  |  * compilers give a warning on unknown #pragmas, which is not so fine... | ||||||
|  |  */ | ||||||
|  | #if defined SN_TARGET_PS2 || defined __GNUC__ | ||||||
|  |   #define AMX_NO_ALIGN | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #if defined __GNUC__ | ||||||
|  |   #define PACKED        __attribute__((packed)) | ||||||
|  | #else | ||||||
|  |   #define PACKED | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #if !defined AMX_NO_ALIGN | ||||||
|  |   #if defined LINUX || defined __FreeBSD__ | ||||||
|  |     #pragma pack(1)         /* structures must be packed (byte-aligned) */ | ||||||
|  |   #elif defined MACOS && defined __MWERKS__ | ||||||
|  | 	#pragma options align=mac68k | ||||||
|  |   #else | ||||||
|  |     #pragma pack(push) | ||||||
|  |     #pragma pack(1)         /* structures must be packed (byte-aligned) */ | ||||||
|  |     #if defined __TURBOC__ | ||||||
|  |       #pragma option -a-    /* "pack" pragma for older Borland compilers */ | ||||||
|  |     #endif | ||||||
|  |   #endif | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | typedef struct tagAMX_DBG_HDR { | ||||||
|  |   int32_t size          PACKED; /* size of the debug information chunk */ | ||||||
|  |   uint16_t magic        PACKED; /* signature, must be 0xf1ef */ | ||||||
|  |   char    file_version  PACKED; /* file format version */ | ||||||
|  |   char    amx_version   PACKED; /* required version of the AMX */ | ||||||
|  |   int16_t flags         PACKED; /* currently unused */ | ||||||
|  |   int16_t files         PACKED; /* number of entries in the "file" table */ | ||||||
|  |   int16_t lines         PACKED; /* number of entries in the "line" table */ | ||||||
|  |   int16_t symbols       PACKED; /* number of entries in the "symbol" table */ | ||||||
|  |   int16_t tags          PACKED; /* number of entries in the "tag" table */ | ||||||
|  |   int16_t automatons    PACKED; /* number of entries in the "automaton" table */ | ||||||
|  |   int16_t states        PACKED; /* number of entries in the "state" table */ | ||||||
|  | } AMX_DBG_HDR           PACKED; | ||||||
|  | #define AMX_DBG_MAGIC   0xf1ef | ||||||
|  |  | ||||||
|  | typedef struct tagAMX_DBG_FILE { | ||||||
|  |   ucell   address       PACKED; /* address in the code segment where generated code (for this file) starts */ | ||||||
|  |   const char name[1]    PACKED; /* ASCII string, zero-terminated */ | ||||||
|  | } AMX_DBG_FILE          PACKED; | ||||||
|  |  | ||||||
|  | typedef struct tagAMX_DBG_LINE { | ||||||
|  |   ucell   address       PACKED; /* address in the code segment where generated code (for this line) starts */ | ||||||
|  |   int32_t line          PACKED; /* line number */ | ||||||
|  | } AMX_DBG_LINE          PACKED; | ||||||
|  |  | ||||||
|  | typedef struct tagAMX_DBG_SYMBOL { | ||||||
|  |   ucell   address       PACKED; /* address in the data segment or relative to the frame */ | ||||||
|  |   int16_t tag           PACKED; /* tag for the symbol */ | ||||||
|  |   ucell   codestart     PACKED; /* address in the code segment from which this symbol is valid (in scope) */ | ||||||
|  |   ucell   codeend       PACKED; /* address in the code segment until which this symbol is valid (in scope) */ | ||||||
|  |   char    ident         PACKED; /* kind of symbol (function/variable) */ | ||||||
|  |   char    vclass        PACKED; /* class of symbol (global/local) */ | ||||||
|  |   int16_t dim           PACKED; /* number of dimensions */ | ||||||
|  |   const char name[1]    PACKED; /* ASCII string, zero-terminated */ | ||||||
|  | } AMX_DBG_SYMBOL        PACKED; | ||||||
|  |  | ||||||
|  | typedef struct tagAMX_DBG_SYMDIM { | ||||||
|  |   int16_t tag           PACKED; /* tag for the array dimension */ | ||||||
|  |   ucell   size          PACKED; /* size of the array dimension */ | ||||||
|  | } AMX_DBG_SYMDIM        PACKED; | ||||||
|  |  | ||||||
|  | typedef struct tagAMX_DBG_TAG { | ||||||
|  |   int16_t tag           PACKED; /* tag id */ | ||||||
|  |   const char name[1]    PACKED; /* ASCII string, zero-terminated */ | ||||||
|  | } AMX_DBG_TAG           PACKED; | ||||||
|  |  | ||||||
|  | typedef struct tagAMX_DBG_MACHINE { | ||||||
|  |   int16_t automaton     PACKED; /* automaton id */ | ||||||
|  |   ucell address         PACKED; /* address of state variable */ | ||||||
|  |   const char name[1]    PACKED; /* ASCII string, zero-terminated */ | ||||||
|  | } AMX_DBG_MACHINE       PACKED; | ||||||
|  |  | ||||||
|  | typedef struct tagAMX_DBG_STATE { | ||||||
|  |   int16_t state         PACKED; /* state id */ | ||||||
|  |   int16_t automaton     PACKED; /* automaton id */ | ||||||
|  |   const char name[1]    PACKED; /* ASCII string, zero-terminated */ | ||||||
|  | } AMX_DBG_STATE         PACKED; | ||||||
|  |  | ||||||
|  | typedef struct tagAMX_DBG { | ||||||
|  |   AMX_DBG_HDR     _FAR *hdr         PACKED; /* points to the AMX_DBG header */ | ||||||
|  |   AMX_DBG_FILE    _FAR **filetbl    PACKED; | ||||||
|  |   AMX_DBG_LINE    _FAR *linetbl     PACKED; | ||||||
|  |   AMX_DBG_SYMBOL  _FAR **symboltbl  PACKED; | ||||||
|  |   AMX_DBG_TAG     _FAR **tagtbl     PACKED; | ||||||
|  |   AMX_DBG_MACHINE _FAR **automatontbl PACKED; | ||||||
|  |   AMX_DBG_STATE   _FAR **statetbl   PACKED; | ||||||
|  | } AMX_DBG                           PACKED; | ||||||
|  |  | ||||||
|  | #if !defined iVARIABLE | ||||||
|  |   #define iVARIABLE  1  /* cell that has an address and that can be fetched directly (lvalue) */ | ||||||
|  |   #define iREFERENCE 2  /* iVARIABLE, but must be dereferenced */ | ||||||
|  |   #define iARRAY     3 | ||||||
|  |   #define iREFARRAY  4  /* an array passed by reference (i.e. a pointer) */ | ||||||
|  |   #define iFUNCTN    9 | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |  | ||||||
|  | int AMXAPI dbg_FreeInfo(AMX_DBG *amxdbg); | ||||||
|  | int AMXAPI dbg_LoadInfo(AMX_DBG *amxdbg, void *dbg_addr); | ||||||
|  |  | ||||||
|  | int AMXAPI dbg_LookupFile(AMX_DBG *amxdbg, ucell address, const char **filename); | ||||||
|  | int AMXAPI dbg_LookupFunction(AMX_DBG *amxdbg, ucell address, const char **funcname); | ||||||
|  | int AMXAPI dbg_LookupLine(AMX_DBG *amxdbg, ucell address, long *line); | ||||||
|  |  | ||||||
|  | int AMXAPI dbg_GetFunctionAddress(AMX_DBG *amxdbg, const char *funcname, const char *filename, ucell *address); | ||||||
|  | int AMXAPI dbg_GetLineAddress(AMX_DBG *amxdbg, long line, const char *filename, ucell *address); | ||||||
|  | int AMXAPI dbg_GetAutomatonName(AMX_DBG *amxdbg, int automaton, const char **name); | ||||||
|  | int AMXAPI dbg_GetStateName(AMX_DBG *amxdbg, int state, const char **name); | ||||||
|  | int AMXAPI dbg_GetTagName(AMX_DBG *amxdbg, int tag, const char **name); | ||||||
|  | int AMXAPI dbg_GetVariable(AMX_DBG *amxdbg, const char *symname, ucell scopeaddr, const AMX_DBG_SYMBOL **sym); | ||||||
|  | int AMXAPI dbg_GetArrayDim(AMX_DBG *amxdbg, const AMX_DBG_SYMBOL *sym, const AMX_DBG_SYMDIM **symdim); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #if !defined AMX_NO_ALIGN | ||||||
|  |   #if defined LINUX || defined __FreeBSD__ | ||||||
|  |     #pragma pack()    /* reset default packing */ | ||||||
|  |   #elif defined MACOS && defined __MWERKS__ | ||||||
|  |     #pragma options align=reset | ||||||
|  |   #else | ||||||
|  |     #pragma pack(pop) /* reset previous packing */ | ||||||
|  |   #endif | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #ifdef  __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #endif /* AMXDBG_H_INCLUDED */ | ||||||
		Reference in New Issue
	
	Block a user