📄 debug.c
字号:
/* debug.c -- Handle generic debugging information.
Copyright 1995, 1996, 1997, 1998, 2000 Free Software Foundation, Inc.
Written by Ian Lance Taylor <ian@cygnus.com>.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
/* This file implements a generic debugging format. We may eventually
have readers which convert different formats into this generic
format, and writers which write it out. The initial impetus for
this was writing a convertor from stabs to HP IEEE-695 debugging
format. */
#include <stdio.h>
#include <assert.h>
#include <bfd.h>
#include "bucomm.h"
#include <libiberty.h>
#include "debug.h"
/* Global information we keep for debugging. A pointer to this
structure is the debugging handle passed to all the routines. */
struct debug_handle
{
/* A linked list of compilation units. */
struct debug_unit *units;
/* The current compilation unit. */
struct debug_unit *current_unit;
/* The current source file. */
struct debug_file *current_file;
/* The current function. */
struct debug_function *current_function;
/* The current block. */
struct debug_block *current_block;
/* The current line number information for the current unit. */
struct debug_lineno *current_lineno;
/* Mark. This is used by debug_write. */
unsigned int mark;
/* A struct/class ID used by debug_write. */
unsigned int class_id;
/* The base for class_id for this call to debug_write. */
unsigned int base_id;
/* The current line number in debug_write. */
struct debug_lineno *current_write_lineno;
unsigned int current_write_lineno_index;
/* A list of classes which have assigned ID's during debug_write.
This is linked through the next_id field of debug_class_type. */
struct debug_class_id *id_list;
/* A list used to avoid recursion during debug_type_samep. */
struct debug_type_compare_list *compare_list;
};
/* Information we keep for a single compilation unit. */
struct debug_unit
{
/* The next compilation unit. */
struct debug_unit *next;
/* A list of files included in this compilation unit. The first
file is always the main one, and that is where the main file name
is stored. */
struct debug_file *files;
/* Line number information for this compilation unit. This is not
stored by function, because assembler code may have line number
information without function information. */
struct debug_lineno *linenos;
};
/* Information kept for a single source file. */
struct debug_file
{
/* The next source file in this compilation unit. */
struct debug_file *next;
/* The name of the source file. */
const char *filename;
/* Global functions, variables, types, etc. */
struct debug_namespace *globals;
};
/* During debug_type_samep, a linked list of these structures is kept
on the stack to avoid infinite recursion. */
struct debug_type_compare_list
{
/* Next type on list. */
struct debug_type_compare_list *next;
/* The types we are comparing. */
struct debug_type *t1;
struct debug_type *t2;
};
/* Local functions. */
static void debug_error PARAMS ((const char *));
static struct debug_name *debug_add_to_namespace
PARAMS ((struct debug_handle *, struct debug_namespace **, const char *,
enum debug_object_kind, enum debug_object_linkage));
static struct debug_name *debug_add_to_current_namespace
PARAMS ((struct debug_handle *, const char *, enum debug_object_kind,
enum debug_object_linkage));
static struct debug_type *debug_make_type
PARAMS ((struct debug_handle *, enum debug_type_kind, unsigned int));
/*static struct debug_type *debug_get_real_type
PARAMS ((PTR, debug_type, struct debug_type_real_list *));*/
static bfd_boolean debug_write_name
PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR,
struct debug_name *));
static bfd_boolean debug_write_type
PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR,
struct debug_type *, struct debug_name *));
static bfd_boolean debug_write_class_type
PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR,
struct debug_type *, const char *));
static bfd_boolean debug_write_function
PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR,
const char *, enum debug_object_linkage, struct debug_function *));
static bfd_boolean debug_write_block
PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR,
struct debug_block *));
static bfd_boolean debug_write_linenos
PARAMS ((struct debug_handle *, const struct debug_write_fns *, PTR,
bfd_vma));
static bfd_boolean debug_set_class_id
PARAMS ((struct debug_handle *, const char *, struct debug_type *));
static bfd_boolean debug_type_samep
PARAMS ((struct debug_handle *, struct debug_type *, struct debug_type *));
static bfd_boolean debug_class_type_samep
PARAMS ((struct debug_handle *, struct debug_type *, struct debug_type *));
struct bfd_hash_entry *string_hash_newfunc
PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
/* Issue an error message. */
static void
debug_error (message)
const char *message;
{
fprintf (stderr, "%s\n", message);
}
/* Add an object to a namespace. */
static struct debug_name *
debug_add_to_namespace (info, nsp, name, kind, linkage)
struct debug_handle *info ATTRIBUTE_UNUSED;
struct debug_namespace **nsp;
const char *name;
enum debug_object_kind kind;
enum debug_object_linkage linkage;
{
struct debug_name *n;
struct debug_namespace *ns;
n = (struct debug_name *) xmalloc (sizeof *n);
memset (n, 0, sizeof *n);
n->name = name;
n->kind = kind;
n->linkage = linkage;
ns = *nsp;
if (ns == NULL)
{
ns = (struct debug_namespace *) xmalloc (sizeof *ns);
memset (ns, 0, sizeof *ns);
ns->tail = &ns->list;
*nsp = ns;
}
*ns->tail = n;
ns->tail = &n->next;
return n;
}
/* Add an object to the current namespace. */
static struct debug_name *
debug_add_to_current_namespace (info, name, kind, linkage)
struct debug_handle *info;
const char *name;
enum debug_object_kind kind;
enum debug_object_linkage linkage;
{
struct debug_namespace **nsp;
if (info->current_unit == NULL
|| info->current_file == NULL)
{
debug_error ("debug_add_to_current_namespace: no current file");
return NULL;
}
if (info->current_block != NULL)
nsp = &info->current_block->locals;
else
nsp = &info->current_file->globals;
return debug_add_to_namespace (info, nsp, name, kind, linkage);
}
/* Return a handle for debugging information. */
PTR
debug_init ()
{
struct debug_handle *ret;
ret = (struct debug_handle *) xmalloc (sizeof *ret);
memset (ret, 0, sizeof *ret);
return (PTR) ret;
}
/* Set the source filename. This implicitly starts a new compilation
unit. */
bfd_boolean
debug_set_filename (handle, name)
PTR handle;
const char *name;
{
struct debug_handle *info = (struct debug_handle *) handle;
struct debug_file *nfile;
struct debug_unit *nunit;
if (name == NULL)
name = "";
nfile = (struct debug_file *) xmalloc (sizeof *nfile);
memset (nfile, 0, sizeof *nfile);
nfile->filename = name;
nunit = (struct debug_unit *) xmalloc (sizeof *nunit);
memset (nunit, 0, sizeof *nunit);
nunit->files = nfile;
info->current_file = nfile;
if (info->current_unit != NULL)
info->current_unit->next = nunit;
else
{
assert (info->units == NULL);
info->units = nunit;
}
info->current_unit = nunit;
info->current_function = NULL;
info->current_block = NULL;
info->current_lineno = NULL;
return true;
}
/* Change source files to the given file name. This is used for
include files in a single compilation unit. */
bfd_boolean
debug_start_source (handle, name)
PTR handle;
const char *name;
{
struct debug_handle *info = (struct debug_handle *) handle;
struct debug_file *f, **pf;
if (name == NULL)
name = "";
if (info->current_unit == NULL)
{
debug_error ("debug_start_source: no debug_set_filename call");
return false;
}
for (f = info->current_unit->files; f != NULL; f = f->next)
{
if (f->filename[0] == name[0]
&& f->filename[1] == name[1]
&& strcmp (f->filename, name) == 0)
{
info->current_file = f;
return true;
}
}
f = (struct debug_file *) xmalloc (sizeof *f);
memset (f, 0, sizeof *f);
f->filename = name;
for (pf = &info->current_file->next;
*pf != NULL;
pf = &(*pf)->next)
;
*pf = f;
info->current_file = f;
return true;
}
/* Record a function definition. This implicitly starts a function
block. The debug_type argument is the type of the return value.
The bfd_boolean indicates whether the function is globally visible.
The bfd_vma is the address of the start of the function. Currently
the parameter types are specified by calls to
debug_record_parameter. FIXME: There is no way to specify nested
functions. */
bfd_boolean
debug_record_function (handle, name, return_type, global, addr)
PTR handle;
const char *name;
debug_type return_type;
bfd_boolean global;
bfd_vma addr;
{
struct debug_handle *info = (struct debug_handle *) handle;
struct debug_function *f;
struct debug_block *b;
struct debug_name *n;
if (name == NULL)
name = "";
if (return_type == NULL)
return false;
if (info->current_unit == NULL)
{
debug_error ("debug_record_function: no debug_set_filename call");
return false;
}
f = (struct debug_function *) xmalloc (sizeof *f);
memset (f, 0, sizeof *f);
f->return_type = return_type;
b = (struct debug_block *) xmalloc (sizeof *b);
memset (b, 0, sizeof *b);
b->start = addr;
b->end = (bfd_vma) -1;
f->blocks = b;
info->current_function = f;
info->current_block = b;
/* FIXME: If we could handle nested functions, this would be the
place: we would want to use a different namespace. */
n = debug_add_to_namespace (info,
&info->current_file->globals,
name,
DEBUG_OBJECT_FUNCTION,
(global
? DEBUG_LINKAGE_GLOBAL
: DEBUG_LINKAGE_STATIC));
if (n == NULL)
return false;
n->u.function = f;
return true;
}
/* Record a parameter for the current function. */
bfd_boolean
debug_record_parameter (handle, name, type, kind, val)
PTR handle;
const char *name;
debug_type type;
enum debug_parm_kind kind;
bfd_vma val;
{
struct debug_handle *info = (struct debug_handle *) handle;
struct debug_parameter *p, **pp;
if (name == NULL || type == NULL)
return false;
if (info->current_unit == NULL
|| info->current_function == NULL)
{
debug_error ("debug_record_parameter: no current function");
return false;
}
p = (struct debug_parameter *) xmalloc (sizeof *p);
memset (p, 0, sizeof *p);
p->name = name;
p->type = type;
p->kind = kind;
p->val = val;
for (pp = &info->current_function->parameters;
*pp != NULL;
pp = &(*pp)->next)
;
*pp = p;
return true;
}
/* End a function. FIXME: This should handle function nesting. */
bfd_boolean
debug_end_function (handle, addr)
PTR handle;
bfd_vma addr;
{
struct debug_handle *info = (struct debug_handle *) handle;
if (info->current_unit == NULL
|| info->current_block == NULL
|| info->current_function == NULL)
{
debug_error ("debug_end_function: no current function");
return false;
}
if (info->current_block->parent != NULL)
{
debug_error ("debug_end_function: some blocks were not closed");
return false;
}
info->current_block->end = addr;
info->current_function = NULL;
info->current_block = NULL;
return true;
}
/* Start a block in a function. All local information will be
recorded in this block, until the matching call to debug_end_block.
debug_start_block and debug_end_block may be nested. The bfd_vma
argument is the address at which this block starts. */
bfd_boolean
debug_start_block (handle, addr)
PTR handle;
bfd_vma addr;
{
struct debug_handle *info = (struct debug_handle *) handle;
struct debug_block *b, **pb;
/* We must always have a current block: debug_record_function sets
one up. */
if (info->current_unit == NULL
|| info->current_block == NULL)
{
debug_error ("debug_start_block: no current block");
return false;
}
b = (struct debug_block *) xmalloc (sizeof *b);
memset (b, 0, sizeof *b);
b->parent = info->current_block;
b->start = addr;
b->end = (bfd_vma) -1;
/* This new block is a child of the current block. */
for (pb = &info->current_block->children;
*pb != NULL;
pb = &(*pb)->next)
;
*pb = b;
info->current_block = b;
return true;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -