From 3ec4b296baa58201780fafbe9021436d09a34794 Mon Sep 17 00:00:00 2001 From: uz Date: Thu, 1 Sep 2011 20:51:07 +0000 Subject: [PATCH] Added functions to access the c symbols in the debug info file. git-svn-id: svn://svn.cc65.org/cc65/trunk@5294 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- src/dbginfo/dbginfo.c | 388 +++++++++++++++++++++++++++++++++++------- src/dbginfo/dbginfo.h | 16 ++ src/dbginfo/dbgsh.c | 175 ++++++++++++++++++- 3 files changed, 514 insertions(+), 65 deletions(-) diff --git a/src/dbginfo/dbginfo.c b/src/dbginfo/dbginfo.c index 9174a6a65..249bdcd04 100644 --- a/src/dbginfo/dbginfo.c +++ b/src/dbginfo/dbginfo.c @@ -265,7 +265,6 @@ struct CSymInfo { unsigned Id; /* Id of scope */ ScopeInfo* Info; /* Pointer to scope */ } Scope; - Collection* LocalsByName; /* Locals if this is a function */ char Name[1]; /* Name of file with full path */ }; @@ -731,9 +730,9 @@ static void CollFree (Collection* C) static unsigned CollCount (const Collection* C) -/* Return the number of items in the collection */ +/* Return the number of items in the collection. Return 0 if C is NULL. */ { - return C->Count; + return C? C->Count : 0; } @@ -1069,6 +1068,21 @@ static void DBGPRINT(const char* format, ...) {} +static unsigned GetId (const void* Data) +/* Return the id of one of the info structures. All structures have the Id + * field as first member, and the C standard allows converting a union pointer + * to the data type of the first member, so this is safe and portable. + */ +{ + if (Data) { + return *(const unsigned*)Data; + } else { + return CC65_INV_ID; + } +} + + + static unsigned HexValue (char C) /* Convert the ascii representation of a hex nibble into the hex nibble */ { @@ -1182,7 +1196,6 @@ static CSymInfo* NewCSymInfo (const StrBuf* Name) CSymInfo* S = xmalloc (sizeof (CSymInfo) + SB_GetLen (Name)); /* Initialize it */ - S->LocalsByName = 0; memcpy (S->Name, SB_GetConstBuf (Name), SB_GetLen (Name) + 1); /* Return it */ @@ -1194,15 +1207,39 @@ static CSymInfo* NewCSymInfo (const StrBuf* Name) static void FreeCSymInfo (CSymInfo* S) /* Free a CSymInfo struct */ { - /* Free collections */ - CollFree (S->LocalsByName); - /* Free the structure itself */ xfree (S); } +static cc65_csyminfo* new_cc65_csyminfo (unsigned Count) +/* Allocate and return a cc65_csyminfo struct that is able to hold Count + * entries. Initialize the count field of the returned struct. + */ +{ + cc65_csyminfo* S = xmalloc (sizeof (*S) - sizeof (S->data[0]) + + Count * sizeof (S->data[0])); + S->count = Count; + return S; +} + + + +static void CopyCSymInfo (cc65_csymdata* D, const CSymInfo* S) +/* Copy data from a CSymInfo struct to a cc65_csymdata struct */ +{ + D->csym_id = S->Id; + D->csym_kind = S->Kind; + D->csym_sc = S->SC; + D->csym_offs = S->Offs; + D->symbol_id = GetId (S->Sym.Info); + D->scope_id = GetId (S->Scope.Info); + D->csym_name = S->Name; +} + + + static int CompareCSymInfoByName (const void* L, const void* R) /* Helper function to sort c symbol infos in a collection by name */ { @@ -1473,19 +1510,11 @@ static cc65_moduleinfo* new_cc65_moduleinfo (unsigned Count) static void CopyModInfo (cc65_moduledata* D, const ModInfo* M) /* Copy data from a ModInfo struct to a cc65_moduledata struct */ { - D->module_id = M->Id; - D->module_name = M->Name; - D->source_id = M->File.Info->Id; - if (M->Lib.Info) { - D->library_id = M->Lib.Info->Id; - } else { - D->library_id = CC65_INV_ID; - } - if (M->MainScope) { - D->scope_id = M->MainScope->Id; - } else { - D->scope_id = CC65_INV_ID; - } + D->module_id = M->Id; + D->module_name = M->Name; + D->source_id = M->File.Info->Id; + D->library_id = GetId (M->Lib.Info); + D->scope_id = GetId (M->MainScope); } @@ -1553,21 +1582,13 @@ static cc65_scopeinfo* new_cc65_scopeinfo (unsigned Count) static void CopyScopeInfo (cc65_scopedata* D, const ScopeInfo* S) /* Copy data from a ScopeInfo struct to a cc65_scopedata struct */ { - D->scope_id = S->Id; - D->scope_name = S->Name; - D->scope_type = S->Type; - D->scope_size = S->Size; - if (S->Parent.Info) { - D->parent_id = S->Parent.Info->Id; - } else { - D->parent_id = CC65_INV_ID; - } - if (S->Label.Info) { - D->symbol_id = S->Label.Info->Id; - } else { - D->symbol_id = CC65_INV_ID; - } - D->module_id = S->Mod.Info->Id; + D->scope_id = S->Id; + D->scope_name = S->Name; + D->scope_type = S->Type; + D->scope_size = S->Size; + D->parent_id = GetId (S->Parent.Info); + D->symbol_id = GetId (S->Label.Info); + D->module_id = S->Mod.Info->Id; } @@ -1714,25 +1735,13 @@ static cc65_spaninfo* new_cc65_spaninfo (unsigned Count) static void CopySpanInfo (cc65_spandata* D, const SpanInfo* S) /* Copy data from a SpanInfo struct to a cc65_spandata struct */ { - D->span_id = S->Id; - D->span_start = S->Start; - D->span_end = S->End; - D->segment_id = S->Seg.Info->Id; - if (S->Type.Info) { - D->type_id = S->Type.Info->Id; - } else { - D->type_id = CC65_INV_ID; - } - if (S->ScopeInfoList) { - D->scope_count = CollCount (S->ScopeInfoList); - } else { - D->scope_count = 0; - } - if (S->LineInfoList) { - D->line_count = CollCount (S->LineInfoList); - } else { - D->line_count = 0; - } + D->span_id = S->Id; + D->span_start = S->Start; + D->span_end = S->End; + D->segment_id = S->Seg.Info->Id; + D->type_id = GetId (S->Type.Info); + D->scope_count = CollCount (S->ScopeInfoList); + D->line_count = CollCount (S->LineInfoList); } @@ -4605,7 +4614,51 @@ ErrorExit: -static int FindFileInfoByName (Collection* FileInfos, const char* Name, +static int FindCSymInfoByName (const Collection* CSymInfos, const char* Name, + unsigned* Index) +/* Find the C symbol info with a given file name. The function returns true if + * the name was found. In this case, Index contains the index of the first item + * that matches. If the item wasn't found, the function returns false and + * Index contains the insert position for Name. + */ +{ + /* Do a binary search */ + int Lo = 0; + int Hi = (int) CollCount (CSymInfos) - 1; + int Found = 0; + while (Lo <= Hi) { + + /* Mid of range */ + int Cur = (Lo + Hi) / 2; + + /* Get item */ + const CSymInfo* CurItem = CollAt (CSymInfos, Cur); + + /* Compare */ + int Res = strcmp (CurItem->Name, Name); + + /* Found? */ + if (Res < 0) { + Lo = Cur + 1; + } else { + Hi = Cur - 1; + /* Since we may have duplicates, repeat the search until we've + * the first item that has a match. + */ + if (Res == 0) { + Found = 1; + } + } + } + + /* Pass back the index. This is also the insert position */ + *Index = Lo; + return Found; +} + + + +static int FindFileInfoByName (const Collection* FileInfos, const char* Name, unsigned* Index) /* Find the FileInfo for a given file name. The function returns true if the * name was found. In this case, Index contains the index of the first item @@ -4623,7 +4676,7 @@ static int FindFileInfoByName (Collection* FileInfos, const char* Name, int Cur = (Lo + Hi) / 2; /* Get item */ - FileInfo* CurItem = CollAt (FileInfos, Cur); + const FileInfo* CurItem = CollAt (FileInfos, Cur); /* Compare */ int Res = strcmp (CurItem->Name, Name); @@ -4965,14 +5018,14 @@ static void ProcessCSymInfo (InputData* D) } } - /* Walk over all scopes and sort the c symbols by name */ + /* Walk over all scopes and sort the c symbols by name. */ for (I = 0; I < CollCount (&D->Info->ScopeInfoById); ++I) { /* Get this scope */ ScopeInfo* S = CollAt (&D->Info->ScopeInfoById, I); /* Ignore scopes without C symbols */ - if (S->CSymInfoByName && CollCount (S->CSymInfoByName) > 1) { + if (CollCount (S->CSymInfoByName) > 1) { /* Sort the c symbols for this scope by name */ CollSort (S->CSymInfoByName, CompareCSymInfoByName); } @@ -5741,6 +5794,217 @@ void cc65_free_dbginfo (cc65_dbginfo Handle) +/*****************************************************************************/ +/* C symbols */ +/*****************************************************************************/ + + + +const cc65_csyminfo* cc65_get_csymlist (cc65_dbginfo Handle) +/* Return a list of all c symbols */ +{ + const DbgInfo* Info; + cc65_csyminfo* S; + unsigned I; + + /* Check the parameter */ + assert (Handle != 0); + + /* The handle is actually a pointer to a debug info struct */ + Info = Handle; + + /* Allocate memory for the data structure returned to the caller */ + S = new_cc65_csyminfo (CollCount (&Info->CSymInfoById)); + + /* Fill in the data */ + for (I = 0; I < CollCount (&Info->CSymInfoById); ++I) { + /* Copy the data */ + CopyCSymInfo (S->data + I, CollAt (&Info->CSymInfoById, I)); + } + + /* Return the result */ + return S; +} + + + +const cc65_csyminfo* cc65_csym_byid (cc65_dbginfo Handle, unsigned Id) +/* Return information about a c symbol with a specific id. The function + * returns NULL if the id is invalid (no such c symbol) and otherwise a + * cc65_csyminfo structure with one entry that contains the requested + * symbol information. + */ +{ + const DbgInfo* Info; + cc65_csyminfo* S; + + /* Check the parameter */ + assert (Handle != 0); + + /* The handle is actually a pointer to a debug info struct */ + Info = Handle; + + /* Check if the id is valid */ + if (Id >= CollCount (&Info->CSymInfoById)) { + return 0; + } + + /* Allocate memory for the data structure returned to the caller */ + S = new_cc65_csyminfo (1); + + /* Fill in the data */ + CopyCSymInfo (S->data, CollAt (&Info->CSymInfoById, Id)); + + /* Return the result */ + return S; +} + + + +const cc65_csyminfo* cc65_cfunc_bymodule (cc65_dbginfo Handle, unsigned ModId) +/* Return the list of C functions (not symbols!) for a specific module. If + * the module id is invalid, the function will return NULL, otherwise a + * (possibly empty) c symbol list. + */ +{ + const DbgInfo* Info; + const ModInfo* M; + cc65_csyminfo* D; + unsigned I; + + + /* Check the parameter */ + assert (Handle != 0); + + /* The handle is actually a pointer to a debug info struct */ + Info = Handle; + + /* Check if the module id is valid */ + if (ModId >= CollCount (&Info->ModInfoById)) { + return 0; + } + + /* Get a pointer to the module info */ + M = CollAt (&Info->ModInfoById, ModId); + + /* Allocate memory for the data structure returned to the caller */ + D = new_cc65_csyminfo (CollCount (&M->CSymFuncByName)); + + /* Fill in the data */ + for (I = 0; I < CollCount (&M->CSymFuncByName); ++I) { + CopyCSymInfo (D->data + I, CollAt (&M->CSymFuncByName, I)); + } + + /* Return the result */ + return D; +} + + + +const cc65_csyminfo* cc65_cfunc_byname (cc65_dbginfo Handle, const char* Name) +/* Return a list of all C functions with the given name that have a + * definition. + */ +{ + const DbgInfo* Info; + unsigned Index; + unsigned Count; + const CSymInfo* S; + cc65_csyminfo* D; + unsigned I; + + + /* Check the parameter */ + assert (Handle != 0); + + /* The handle is actually a pointer to a debug info struct */ + Info = Handle; + + /* Search for a function with the given name */ + if (!FindCSymInfoByName (&Info->CSymFuncByName, Name, &Index)) { + return 0; + } + + /* Count functions with this name */ + Count = 1; + I = Index; + while (1) { + if (++I >= CollCount (&Info->CSymFuncByName)) { + break; + } + S = CollAt (&Info->CSymFuncByName, I); + if (strcmp (S->Name, Name) != 0) { + /* Next symbol has another name */ + break; + } + ++Count; + } + + /* Allocate memory for the data structure returned to the caller */ + D = new_cc65_csyminfo (Count); + + /* Fill in the data */ + for (I = 0; I < Count; ++I, ++Index) { + CopyCSymInfo (D->data + I, CollAt (&Info->CSymFuncByName, Index)); + } + + /* Return the result */ + return D; +} + + + +const cc65_csyminfo* cc65_csym_byscope (cc65_dbginfo Handle, unsigned ScopeId) +/* Return all C symbols for a scope. The function will return NULL if the + * given id is invalid. + */ +{ + const DbgInfo* Info; + const ScopeInfo* S; + cc65_csyminfo* D; + unsigned I; + + + /* Check the parameter */ + assert (Handle != 0); + + /* The handle is actually a pointer to a debug info struct */ + Info = Handle; + + /* Check if the scope id is valid */ + if (ScopeId >= CollCount (&Info->ScopeInfoById)) { + return 0; + } + + /* Get a pointer to the scope */ + S = CollAt (&Info->ScopeInfoById, ScopeId); + + /* Allocate memory for the data structure returned to the caller */ + D = new_cc65_csyminfo (CollCount (S->CSymInfoByName)); + + /* Fill in the data */ + for (I = 0; I < CollCount (S->CSymInfoByName); ++I) { + CopyCSymInfo (D->data + I, CollAt (S->CSymInfoByName, I)); + } + + /* Return the result */ + return D; +} + + + +void cc65_free_csyminfo (cc65_dbginfo Handle, const cc65_csyminfo* Info) +/* Free a c symbol info record */ +{ + /* Just for completeness, check the handle */ + assert (Handle != 0); + + /* Just free the memory */ + xfree ((cc65_csyminfo*) Info); +} + + + /*****************************************************************************/ /* Libraries */ /*****************************************************************************/ @@ -6046,9 +6310,9 @@ const cc65_lineinfo* cc65_line_byspan (cc65_dbginfo Handle, unsigned SpanId) S = CollAt (&Info->SpanInfoById, SpanId); /* Prepare the struct we will return to the caller */ - D = new_cc65_lineinfo (S->LineInfoList? CollCount (S->LineInfoList) : 0); + D = new_cc65_lineinfo (CollCount (S->LineInfoList)); - /* Fill in the data. Since D->LineInfoList may be NULL, we will use the + /* Fill in the data. Since S->LineInfoList may be NULL, we will use the * count field of the returned data struct instead. */ for (I = 0; I < D->count; ++I) { @@ -6652,7 +6916,7 @@ const cc65_scopeinfo* cc65_scope_byspan (cc65_dbginfo Handle, unsigned SpanId) S = CollAt (&Info->SpanInfoById, SpanId); /* Prepare the struct we will return to the caller */ - D = new_cc65_scopeinfo (S->ScopeInfoList? CollCount (S->ScopeInfoList) : 0); + D = new_cc65_scopeinfo (CollCount (S->ScopeInfoList)); /* Fill in the data. Since D->ScopeInfoList may be NULL, we will use the * count field of the returned data struct instead. @@ -6694,7 +6958,7 @@ const cc65_scopeinfo* cc65_childscopes_byid (cc65_dbginfo Handle, unsigned Id) S = CollAt (&Info->ScopeInfoById, Id); /* Allocate memory for the data structure returned to the caller */ - D = new_cc65_scopeinfo (S->ChildScopeList? CollCount (S->ChildScopeList) : 0); + D = new_cc65_scopeinfo (CollCount (S->ChildScopeList)); /* Fill in the data */ for (I = 0; I < D->count; ++I) { diff --git a/src/dbginfo/dbginfo.h b/src/dbginfo/dbginfo.h index a2b8cf4ba..aa357a4ba 100644 --- a/src/dbginfo/dbginfo.h +++ b/src/dbginfo/dbginfo.h @@ -158,6 +158,22 @@ const cc65_csyminfo* cc65_csym_byid (cc65_dbginfo handle, unsigned id); * symbol information. */ +const cc65_csyminfo* cc65_cfunc_bymodule (cc65_dbginfo handle, unsigned module_id); +/* Return the list of C functions (not symbols!) for a specific module. If + * the module id is invalid, the function will return NULL, otherwise a + * (possibly empty) c symbol list. + */ + +const cc65_csyminfo* cc65_cfunc_byname (cc65_dbginfo handle, const char* name); +/* Return a list of all C functions with the given name that have a + * definition. + */ + +const cc65_csyminfo* cc65_csym_byscope (cc65_dbginfo handle, unsigned scope_id); +/* Return all C symbols for a scope. The function will return NULL if the + * given id is invalid. + */ + void cc65_free_csyminfo (cc65_dbginfo handle, const cc65_csyminfo* info); /* Free a c symbol info record */ diff --git a/src/dbginfo/dbgsh.c b/src/dbginfo/dbgsh.c index b554c7b52..48b042616 100644 --- a/src/dbginfo/dbgsh.c +++ b/src/dbginfo/dbgsh.c @@ -75,6 +75,12 @@ static void CmdShowHelp (Collection* Args); static void CmdShowChildScopes (Collection* Args); /* Show child scopes from the debug info file */ +static void CmdShowCSymbol (Collection* Args); +/* Show c symbols from the debug info file */ + +static void CmdShowFunction (Collection* Args); +/* Show C functions from the debug info file */ + static void CmdShowLibrary (Collection* Args); /* Show libraries from the debug info file */ @@ -132,6 +138,7 @@ static unsigned FileWarnings = 0; /* Type of an id */ enum { InvalidId, + CSymbolId, LibraryId, LineId, ModuleId, @@ -194,9 +201,29 @@ static const CmdEntry ShowCmds[] = { "Show child scopes of other scopes.", -2, CmdShowChildScopes + }, { + "csym", + 0, + -1, + CmdShowCSymbol + }, { + "csymbol", + "Show c symbols.", + -1, + CmdShowCSymbol + }, { + "func", + 0, + -2, + CmdShowFunction + }, { + "function", + "Show c functions.", + -2, + CmdShowFunction }, { "help", - "Show available subcommands", + "Show available subcommands.", 1, CmdShowHelp }, { @@ -491,10 +518,10 @@ static void PrintAddr (cc65_addr Addr, unsigned FieldWidth) -static void PrintNumber (unsigned long Num, unsigned Width, unsigned FieldWidth) +static void PrintNumber (long Num, unsigned Width, unsigned FieldWidth) /* Output a number */ { - Print ("%*lu", Width, Num); + Print ("%*ld", Width, Num); if (FieldWidth > Width) { Print ("%*s", FieldWidth - Width, ""); } @@ -544,6 +571,38 @@ static void PrintTime (time_t T, unsigned FieldWidth) +static void PrintCSymbolHeader (void) +/* Output a header for a list of C symbols */ +{ + /* Header */ + PrintLine (" id name type kind sc offs symbol scope"); + PrintSeparator (); +} + + + +static void PrintCSymbols (const cc65_csyminfo* S) +/* Output a list of C symbols */ +{ + unsigned I; + const cc65_csymdata* D; + + /* Segments */ + for (I = 0, D = S->data; I < S->count; ++I, ++D) { + PrintId (D->csym_id, 6); + Print ("%-28s", D->csym_name); + PrintId (0, 6); + PrintNumber (D->csym_kind, 4, 6); + PrintNumber (D->csym_sc, 4, 6); + PrintNumber (D->csym_offs, 4, 8); + PrintId (D->symbol_id, 6); + PrintId (D->scope_id, 0); + NewLine (); + } +} + + + static void PrintLibraryHeader (void) /* Output the header for a library list */ { @@ -1002,6 +1061,116 @@ static void CmdShowChildScopes (Collection* Args) +static void CmdShowCSymbol (Collection* Args) +/* Show C symbols from the debug info file */ +{ + const cc65_csyminfo* S; + + /* Be sure a file is loaded */ + if (!FileIsLoaded ()) { + return; + } + + /* Output the header */ + PrintCSymbolHeader (); + + /* No arguments means show all libraries */ + if (CollCount (Args) == 0) { + + /* Fetch the list of c symbols */ + S = cc65_get_csymlist (Info); + + /* Output the c symbols */ + PrintCSymbols (S); + + /* Free the list */ + cc65_free_csyminfo (Info, S); + + } else { + + /* Output c symbols for all arguments */ + unsigned I; + for (I = 0; I < CollCount (Args); ++I) { + + /* Parse the argument */ + unsigned Id; + unsigned IdType = CSymbolId; + if (GetId (CollConstAt (Args, I), &Id, &IdType)) { + /* Fetch list depending on type */ + switch (IdType) { + case CSymbolId: + S = cc65_csym_byid (Info, Id); + break; + case ScopeId: + S = cc65_csym_byscope (Info, Id); + break; + default: + S = 0; + PrintLine ("Invalid id type"); + break; + } + } else { + /* Invalid id */ + S = 0; + } + + /* Output the list */ + if (S) { + PrintCSymbols (S); + cc65_free_csyminfo (Info, S); + } + } + } +} + + + +static void CmdShowFunction (Collection* Args) +/* Show C functions from the debug info file */ +{ + const cc65_csyminfo* S; + unsigned I; + + /* Be sure a file is loaded */ + if (!FileIsLoaded ()) { + return; + } + + /* Output the header */ + PrintCSymbolHeader (); + + /* Output c symbols for all arguments */ + for (I = 0; I < CollCount (Args); ++I) { + + /* Parse the argument */ + unsigned Id; + unsigned IdType = ModuleId; + if (GetId (CollConstAt (Args, I), &Id, &IdType)) { + /* Fetch list depending on type */ + switch (IdType) { + case ModuleId: + S = cc65_cfunc_bymodule (Info, Id); + break; + default: + S = 0; + PrintLine ("Invalid id type"); + break; + } + } else { + /* An invalid id may be a function name */ + S = cc65_cfunc_byname (Info, CollConstAt (Args, I)); + } + + /* Output the list */ + if (S) { + PrintCSymbols (S); + cc65_free_csyminfo (Info, S); + } + } +} + + + static void CmdShowLine (Collection* Args) /* Show lines from the debug info file */ { -- 2.39.5