⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 debug.c

📁 java 反射机制详解示例,实现类属性及方法修改
💻 C
📖 第 1 页 / 共 5 页
字号:
/* 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 + -