From 4b9425cf3b9cfb152d4212f59e7aa3334dfc92c1 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 26 Jul 2005 21:28:19 +0000 Subject: [PATCH] Initial import of edited debug reader --- amxmodx/amxdbg.cpp | 498 +++++++++++++++++++++++++++++++++++++++++++++ amxmodx/amxdbg.h | 172 ++++++++++++++++ 2 files changed, 670 insertions(+) create mode 100755 amxmodx/amxdbg.cpp create mode 100755 amxmodx/amxdbg.h diff --git a/amxmodx/amxdbg.cpp b/amxmodx/amxdbg.cpp new file mode 100755 index 00000000..7f05afb7 --- /dev/null +++ b/amxmodx/amxdbg.cpp @@ -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 +#include +#include +#include +#include +#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; ihdr = (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;indexhdr->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; +} diff --git a/amxmodx/amxdbg.h b/amxmodx/amxdbg.h new file mode 100755 index 00000000..57235933 --- /dev/null +++ b/amxmodx/amxdbg.h @@ -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 */