gdb/
2006-09-21 Vladimir Prus <vladimir@codesourcery.com> Daniel Jacobowitz <dan@codesourcery.com> Nathan Sidwell <nathan@codesourcery.com> * Makefile.in (SFILES): Add memory-map.c and xml-support.c. (memory_map_h, xml_support_h): New. (target_h): Add vec_h dependency. (COMMON_OBS): Add memory-map.o and xml-support.o. (memory-map.o, xml-support.o): New rules. (remote.o): Update. * exceptions.h (enum errors): Add XML_PARSE_ERROR. * infcmd.c (run_command_1, attach_command): Call target_pre_inferior. * memattr.c (default_mem_attrib): Initialize blocksize. (target_mem_region_list, mem_use_target) (target_mem_regions_valid, mem_region_cmp, mem_region_init) (require_user_regions, require_target_regions) (invalidate_target_mem_regions): New. (create_mem_region): Use mem_region_init. (mem_clear): Move higher. (lookup_mem_region): Use require_target_regions. (mem_command): Implement "mem auto". (mem_info_command): Handle target-supplied regions and flash attributes. (mem_enable_command, mem_disable_command, mem_delete_command): Use require_user_regions. (_initialize_mem): Mention "mem auto" in help. * memattr.h (enum mem_access_mode): Add MEM_FLASH. (struct mem_attrib): Add blocksize. (invalidate_target_mem_regions, mem_region_init, mem_region_cmp): New prototypes. * remote.c: Include "memory-map.h". (PACKET_qXfer_memory_map): New enum value. (remote_protocol_features): Add qXfer:memory-map:read. (remote_xfer_partial): Handle memory maps. (remote_memory_map): New. (init_remote_ops, init_remote_async_ops): Set to_memory_map. (_initialize_remote): Register qXfer:memory-map:read. * target.c (update_current_target): Mention to_memory_map. (target_memory_map, target_pre_inferior): New. (target_preopen): Call target_pre_inferior. * target.h: Include "vec.h". (enum target_object): Add TARGET_OBJECT_MEMORY_MAP. (struct target_ops): Add to_memory_map. (target_memory_map, target_pre_inferior): New prototypes. * memory-map.c, memory-map.h, xml-support.c, xml-support.h: New files. gdb/doc/ 2006-09-21 Vladimir Prus <vladimir@codesourcery.com> Daniel Jacobowitz <dan@codesourcery.com> * gdb.texinfo (Memory Region Attributes): Mention target-supplied memory regions and "mem auto".
This commit is contained in:
parent
253c8abb67
commit
fd79eceebf
15 changed files with 875 additions and 24 deletions
|
@ -1,3 +1,49 @@
|
||||||
|
2006-09-21 Vladimir Prus <vladimir@codesourcery.com>
|
||||||
|
Daniel Jacobowitz <dan@codesourcery.com>
|
||||||
|
Nathan Sidwell <nathan@codesourcery.com>
|
||||||
|
|
||||||
|
* Makefile.in (SFILES): Add memory-map.c and xml-support.c.
|
||||||
|
(memory_map_h, xml_support_h): New.
|
||||||
|
(target_h): Add vec_h dependency.
|
||||||
|
(COMMON_OBS): Add memory-map.o and xml-support.o.
|
||||||
|
(memory-map.o, xml-support.o): New rules.
|
||||||
|
(remote.o): Update.
|
||||||
|
* exceptions.h (enum errors): Add XML_PARSE_ERROR.
|
||||||
|
* infcmd.c (run_command_1, attach_command): Call target_pre_inferior.
|
||||||
|
* memattr.c (default_mem_attrib): Initialize blocksize.
|
||||||
|
(target_mem_region_list, mem_use_target)
|
||||||
|
(target_mem_regions_valid, mem_region_cmp, mem_region_init)
|
||||||
|
(require_user_regions, require_target_regions)
|
||||||
|
(invalidate_target_mem_regions): New.
|
||||||
|
(create_mem_region): Use mem_region_init.
|
||||||
|
(mem_clear): Move higher.
|
||||||
|
(lookup_mem_region): Use require_target_regions.
|
||||||
|
(mem_command): Implement "mem auto".
|
||||||
|
(mem_info_command): Handle target-supplied regions and flash
|
||||||
|
attributes.
|
||||||
|
(mem_enable_command, mem_disable_command, mem_delete_command): Use
|
||||||
|
require_user_regions.
|
||||||
|
(_initialize_mem): Mention "mem auto" in help.
|
||||||
|
* memattr.h (enum mem_access_mode): Add MEM_FLASH.
|
||||||
|
(struct mem_attrib): Add blocksize.
|
||||||
|
(invalidate_target_mem_regions, mem_region_init, mem_region_cmp): New
|
||||||
|
prototypes.
|
||||||
|
* remote.c: Include "memory-map.h".
|
||||||
|
(PACKET_qXfer_memory_map): New enum value.
|
||||||
|
(remote_protocol_features): Add qXfer:memory-map:read.
|
||||||
|
(remote_xfer_partial): Handle memory maps.
|
||||||
|
(remote_memory_map): New.
|
||||||
|
(init_remote_ops, init_remote_async_ops): Set to_memory_map.
|
||||||
|
(_initialize_remote): Register qXfer:memory-map:read.
|
||||||
|
* target.c (update_current_target): Mention to_memory_map.
|
||||||
|
(target_memory_map, target_pre_inferior): New.
|
||||||
|
(target_preopen): Call target_pre_inferior.
|
||||||
|
* target.h: Include "vec.h".
|
||||||
|
(enum target_object): Add TARGET_OBJECT_MEMORY_MAP.
|
||||||
|
(struct target_ops): Add to_memory_map.
|
||||||
|
(target_memory_map, target_pre_inferior): New prototypes.
|
||||||
|
* memory-map.c, memory-map.h, xml-support.c, xml-support.h: New files.
|
||||||
|
|
||||||
2006-09-21 Daniel Jacobowitz <dan@codesourcery.com>
|
2006-09-21 Daniel Jacobowitz <dan@codesourcery.com>
|
||||||
|
|
||||||
* ada-lex.l (HIGH_BYTE_POSN, is_digit_in_base, digit_to_int)
|
* ada-lex.l (HIGH_BYTE_POSN, is_digit_in_base, digit_to_int)
|
||||||
|
|
|
@ -541,7 +541,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c \
|
||||||
language.c linespec.c \
|
language.c linespec.c \
|
||||||
m2-exp.y m2-lang.c m2-typeprint.c m2-valprint.c \
|
m2-exp.y m2-lang.c m2-typeprint.c m2-valprint.c \
|
||||||
macrotab.c macroexp.c macrocmd.c macroscope.c main.c maint.c \
|
macrotab.c macroexp.c macrocmd.c macroscope.c main.c maint.c \
|
||||||
mdebugread.c memattr.c mem-break.c minsyms.c mipsread.c \
|
mdebugread.c memattr.c mem-break.c minsyms.c mipsread.c memory-map.c \
|
||||||
nlmread.c \
|
nlmread.c \
|
||||||
objc-exp.y objc-lang.c \
|
objc-exp.y objc-lang.c \
|
||||||
objfiles.c osabi.c observer.c \
|
objfiles.c osabi.c observer.c \
|
||||||
|
@ -561,7 +561,8 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c \
|
||||||
ui-out.c utils.c ui-file.h ui-file.c \
|
ui-out.c utils.c ui-file.h ui-file.c \
|
||||||
user-regs.c \
|
user-regs.c \
|
||||||
valarith.c valops.c valprint.c value.c varobj.c vec.c \
|
valarith.c valops.c valprint.c value.c varobj.c vec.c \
|
||||||
wrapper.c
|
wrapper.c \
|
||||||
|
xml-support.c
|
||||||
|
|
||||||
LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
|
LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
|
||||||
|
|
||||||
|
@ -752,6 +753,7 @@ mips_linux_tdep_h = mips-linux-tdep.h
|
||||||
mips_mdebug_tdep_h = mips-mdebug-tdep.h
|
mips_mdebug_tdep_h = mips-mdebug-tdep.h
|
||||||
mipsnbsd_tdep_h = mipsnbsd-tdep.h
|
mipsnbsd_tdep_h = mipsnbsd-tdep.h
|
||||||
mips_tdep_h = mips-tdep.h
|
mips_tdep_h = mips-tdep.h
|
||||||
|
memory_map_h = memory-map.h $(memattr_h)
|
||||||
mn10300_tdep_h = mn10300-tdep.h
|
mn10300_tdep_h = mn10300-tdep.h
|
||||||
monitor_h = monitor.h
|
monitor_h = monitor.h
|
||||||
nbsd_tdep_h = nbsd-tdep.h
|
nbsd_tdep_h = nbsd-tdep.h
|
||||||
|
@ -801,7 +803,7 @@ stabsread_h = stabsread.h
|
||||||
stack_h = stack.h
|
stack_h = stack.h
|
||||||
symfile_h = symfile.h
|
symfile_h = symfile.h
|
||||||
symtab_h = symtab.h
|
symtab_h = symtab.h
|
||||||
target_h = target.h $(bfd_h) $(symtab_h) $(dcache_h) $(memattr_h)
|
target_h = target.h $(bfd_h) $(symtab_h) $(dcache_h) $(memattr_h) $(vec_h)
|
||||||
terminal_h = terminal.h
|
terminal_h = terminal.h
|
||||||
top_h = top.h
|
top_h = top.h
|
||||||
tracepoint_h = tracepoint.h
|
tracepoint_h = tracepoint.h
|
||||||
|
@ -821,6 +823,7 @@ version_h = version.h
|
||||||
wince_stub_h = wince-stub.h
|
wince_stub_h = wince-stub.h
|
||||||
wrapper_h = wrapper.h $(gdb_h)
|
wrapper_h = wrapper.h $(gdb_h)
|
||||||
xcoffsolib_h = xcoffsolib.h
|
xcoffsolib_h = xcoffsolib.h
|
||||||
|
xml_support_h = xml-support.h
|
||||||
|
|
||||||
#
|
#
|
||||||
# gdb/cli/ headers
|
# gdb/cli/ headers
|
||||||
|
@ -961,7 +964,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
|
||||||
trad-frame.o \
|
trad-frame.o \
|
||||||
tramp-frame.o \
|
tramp-frame.o \
|
||||||
solib.o solib-null.o \
|
solib.o solib-null.o \
|
||||||
prologue-value.o
|
prologue-value.o memory-map.o xml-support.o
|
||||||
|
|
||||||
TSOBS = inflow.o
|
TSOBS = inflow.o
|
||||||
|
|
||||||
|
@ -2371,6 +2374,8 @@ mips-tdep.o: mips-tdep.c $(defs_h) $(gdb_string_h) $(gdb_assert_h) \
|
||||||
$(floatformat_h)
|
$(floatformat_h)
|
||||||
mipsv4-nat.o: mipsv4-nat.c $(defs_h) $(inferior_h) $(gdbcore_h) $(target_h) \
|
mipsv4-nat.o: mipsv4-nat.c $(defs_h) $(inferior_h) $(gdbcore_h) $(target_h) \
|
||||||
$(regcache_h) $(gregset_h)
|
$(regcache_h) $(gregset_h)
|
||||||
|
memory-map.o: memory-map.c $(defs_h) $(memory_map_h) $(xml_support_h) \
|
||||||
|
$(gdb_assert_h) $(exceptions_h) $(gdb_string_h)
|
||||||
mn10300-linux-tdep.o: mn10300-linux-tdep.c $(defs_h) $(gdbcore_h) \
|
mn10300-linux-tdep.o: mn10300-linux-tdep.c $(defs_h) $(gdbcore_h) \
|
||||||
$(gdb_string_h) $(regcache_h) $(mn10300_tdep_h) $(gdb_assert_h) \
|
$(gdb_string_h) $(regcache_h) $(mn10300_tdep_h) $(gdb_assert_h) \
|
||||||
$(bfd_h) $(elf_bfd_h) $(osabi_h) $(regset_h) $(solib_svr4_h) \
|
$(bfd_h) $(elf_bfd_h) $(osabi_h) $(regset_h) $(solib_svr4_h) \
|
||||||
|
@ -2500,7 +2505,7 @@ remote.o: remote.c $(defs_h) $(gdb_string_h) $(inferior_h) $(bfd_h) \
|
||||||
$(gdb_stabs_h) $(gdbthread_h) $(remote_h) $(regcache_h) $(value_h) \
|
$(gdb_stabs_h) $(gdbthread_h) $(remote_h) $(regcache_h) $(value_h) \
|
||||||
$(gdb_assert_h) $(event_loop_h) $(event_top_h) $(inf_loop_h) \
|
$(gdb_assert_h) $(event_loop_h) $(event_top_h) $(inf_loop_h) \
|
||||||
$(serial_h) $(gdbcore_h) $(remote_fileio_h) $(solib_h) $(observer_h) \
|
$(serial_h) $(gdbcore_h) $(remote_fileio_h) $(solib_h) $(observer_h) \
|
||||||
$(cli_decode_h) $(cli_setshow_h)
|
$(cli_decode_h) $(cli_setshow_h) $(memory_map_h)
|
||||||
remote-e7000.o: remote-e7000.c $(defs_h) $(gdbcore_h) $(gdbarch_h) \
|
remote-e7000.o: remote-e7000.c $(defs_h) $(gdbcore_h) $(gdbarch_h) \
|
||||||
$(inferior_h) $(target_h) $(value_h) $(command_h) $(gdb_string_h) \
|
$(inferior_h) $(target_h) $(value_h) $(command_h) $(gdb_string_h) \
|
||||||
$(exceptions_h) $(gdbcmd_h) $(serial_h) $(remote_utils_h) \
|
$(exceptions_h) $(gdbcmd_h) $(serial_h) $(remote_utils_h) \
|
||||||
|
@ -2847,6 +2852,8 @@ xcoffread.o: xcoffread.c $(defs_h) $(bfd_h) $(gdb_string_h) $(gdb_stat_h) \
|
||||||
$(complaints_h) $(gdb_stabs_h) $(aout_stab_gnu_h)
|
$(complaints_h) $(gdb_stabs_h) $(aout_stab_gnu_h)
|
||||||
xcoffsolib.o: xcoffsolib.c $(defs_h) $(bfd_h) $(xcoffsolib_h) $(inferior_h) \
|
xcoffsolib.o: xcoffsolib.c $(defs_h) $(bfd_h) $(xcoffsolib_h) $(inferior_h) \
|
||||||
$(gdbcmd_h) $(symfile_h) $(frame_h) $(gdb_regex_h)
|
$(gdbcmd_h) $(symfile_h) $(frame_h) $(gdb_regex_h)
|
||||||
|
xml-support.o: xml-support.c $(defs_h) $(xml_support_h) $(exceptions_h) \
|
||||||
|
$(gdb_string_h)
|
||||||
xstormy16-tdep.o: xstormy16-tdep.c $(defs_h) $(frame_h) $(frame_base_h) \
|
xstormy16-tdep.o: xstormy16-tdep.c $(defs_h) $(frame_h) $(frame_base_h) \
|
||||||
$(frame_unwind_h) $(dwarf2_frame_h) $(symtab_h) $(gdbtypes_h) \
|
$(frame_unwind_h) $(dwarf2_frame_h) $(symtab_h) $(gdbtypes_h) \
|
||||||
$(gdbcmd_h) $(gdbcore_h) $(value_h) $(dis_asm_h) $(inferior_h) \
|
$(gdbcmd_h) $(gdbcore_h) $(value_h) $(dis_asm_h) $(inferior_h) \
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
|
2006-09-21 Vladimir Prus <vladimir@codesourcery.com>
|
||||||
|
Daniel Jacobowitz <dan@codesourcery.com>
|
||||||
|
|
||||||
|
* gdb.texinfo (Memory Region Attributes): Mention target-supplied
|
||||||
|
memory regions and "mem auto".
|
||||||
|
|
||||||
2006-09-21 Nathan Sidwell <nathan@codesourcery.com>
|
2006-09-21 Nathan Sidwell <nathan@codesourcery.com>
|
||||||
|
|
||||||
* gdbint.texinfo (Array Containers): New section.
|
* gdbint.texinfo (Array Containers): New section.
|
||||||
|
|
|
@ -6720,9 +6720,12 @@ an unrecognized tag.
|
||||||
@cindex memory region attributes
|
@cindex memory region attributes
|
||||||
|
|
||||||
@dfn{Memory region attributes} allow you to describe special handling
|
@dfn{Memory region attributes} allow you to describe special handling
|
||||||
required by regions of your target's memory. @value{GDBN} uses attributes
|
required by regions of your target's memory. @value{GDBN} uses
|
||||||
to determine whether to allow certain types of memory accesses; whether to
|
attributes to determine whether to allow certain types of memory
|
||||||
use specific width accesses; and whether to cache target memory.
|
accesses; whether to use specific width accesses; and whether to cache
|
||||||
|
target memory. By default the description of memory regions is
|
||||||
|
fetched from the target (if the current target supports this), but the
|
||||||
|
user can override the fetched regions.
|
||||||
|
|
||||||
Defined memory regions can be individually enabled and disabled. When a
|
Defined memory regions can be individually enabled and disabled. When a
|
||||||
memory region is disabled, @value{GDBN} uses the default attributes when
|
memory region is disabled, @value{GDBN} uses the default attributes when
|
||||||
|
@ -6742,6 +6745,10 @@ monitored by @value{GDBN}. Note that @var{upper} == 0 is a special
|
||||||
case: it is treated as the the target's maximum memory address.
|
case: it is treated as the the target's maximum memory address.
|
||||||
(0xffff on 16 bit targets, 0xffffffff on 32 bit targets, etc.)
|
(0xffff on 16 bit targets, 0xffffffff on 32 bit targets, etc.)
|
||||||
|
|
||||||
|
@item mem auto
|
||||||
|
Discard any user changes to the memory regions and use target-supplied
|
||||||
|
regions, if available, or no regions if the target does not support.
|
||||||
|
|
||||||
@kindex delete mem
|
@kindex delete mem
|
||||||
@item delete mem @var{nums}@dots{}
|
@item delete mem @var{nums}@dots{}
|
||||||
Remove memory regions @var{nums}@dots{} from the list of regions
|
Remove memory regions @var{nums}@dots{} from the list of regions
|
||||||
|
|
|
@ -71,6 +71,9 @@ enum errors {
|
||||||
more detail. */
|
more detail. */
|
||||||
TLS_GENERIC_ERROR,
|
TLS_GENERIC_ERROR,
|
||||||
|
|
||||||
|
/* Problem parsing an XML document. */
|
||||||
|
XML_PARSE_ERROR,
|
||||||
|
|
||||||
/* Add more errors here. */
|
/* Add more errors here. */
|
||||||
NR_ERRORS
|
NR_ERRORS
|
||||||
};
|
};
|
||||||
|
|
|
@ -468,6 +468,10 @@ run_command_1 (char *args, int from_tty, int tbreak_at_main)
|
||||||
kill_if_already_running (from_tty);
|
kill_if_already_running (from_tty);
|
||||||
clear_breakpoint_hit_counts ();
|
clear_breakpoint_hit_counts ();
|
||||||
|
|
||||||
|
/* Clean up any leftovers from other runs. Some other things from
|
||||||
|
this function should probably be moved into target_pre_inferior. */
|
||||||
|
target_pre_inferior (from_tty);
|
||||||
|
|
||||||
/* Purge old solib objfiles. */
|
/* Purge old solib objfiles. */
|
||||||
objfile_purge_solibs ();
|
objfile_purge_solibs ();
|
||||||
|
|
||||||
|
@ -1847,6 +1851,10 @@ attach_command (char *args, int from_tty)
|
||||||
error (_("Not killed."));
|
error (_("Not killed."));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Clean up any leftovers from other runs. Some other things from
|
||||||
|
this function should probably be moved into target_pre_inferior. */
|
||||||
|
target_pre_inferior (from_tty);
|
||||||
|
|
||||||
/* Clear out solib state. Otherwise the solib state of the previous
|
/* Clear out solib state. Otherwise the solib state of the previous
|
||||||
inferior might have survived and is entirely wrong for the new
|
inferior might have survived and is entirely wrong for the new
|
||||||
target. This has been observed on Linux using glibc 2.3. How to
|
target. This has been observed on Linux using glibc 2.3. How to
|
||||||
|
|
170
gdb/memattr.c
170
gdb/memattr.c
|
@ -36,12 +36,23 @@ const struct mem_attrib default_mem_attrib =
|
||||||
MEM_WIDTH_UNSPECIFIED,
|
MEM_WIDTH_UNSPECIFIED,
|
||||||
0, /* hwbreak */
|
0, /* hwbreak */
|
||||||
0, /* cache */
|
0, /* cache */
|
||||||
0 /* verify */
|
0, /* verify */
|
||||||
|
-1 /* Flash blocksize not specified. */
|
||||||
};
|
};
|
||||||
|
|
||||||
VEC(mem_region_s) *mem_region_list;
|
VEC(mem_region_s) *mem_region_list, *target_mem_region_list;
|
||||||
static int mem_number = 0;
|
static int mem_number = 0;
|
||||||
|
|
||||||
|
/* If this flag is set, the memory region list should be automatically
|
||||||
|
updated from the target. If it is clear, the list is user-controlled
|
||||||
|
and should be left alone. */
|
||||||
|
static int mem_use_target = 1;
|
||||||
|
|
||||||
|
/* If this flag is set, we have tried to fetch the target memory regions
|
||||||
|
since the last time it was invalidated. If that list is still
|
||||||
|
empty, then the target can't supply memory regions. */
|
||||||
|
static int target_mem_regions_valid;
|
||||||
|
|
||||||
/* Predicate function which returns true if LHS should sort before RHS
|
/* Predicate function which returns true if LHS should sort before RHS
|
||||||
in a list of memory regions, useful for VEC_lower_bound. */
|
in a list of memory regions, useful for VEC_lower_bound. */
|
||||||
|
|
||||||
|
@ -52,6 +63,84 @@ mem_region_lessthan (const struct mem_region *lhs,
|
||||||
return lhs->lo < rhs->lo;
|
return lhs->lo < rhs->lo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* A helper function suitable for qsort, used to sort a
|
||||||
|
VEC(mem_region_s) by starting address. */
|
||||||
|
|
||||||
|
int
|
||||||
|
mem_region_cmp (const void *untyped_lhs, const void *untyped_rhs)
|
||||||
|
{
|
||||||
|
const struct mem_region *lhs = untyped_lhs;
|
||||||
|
const struct mem_region *rhs = untyped_rhs;
|
||||||
|
|
||||||
|
if (lhs->lo < rhs->lo)
|
||||||
|
return -1;
|
||||||
|
else if (lhs->lo == rhs->lo)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate a new memory region, with default settings. */
|
||||||
|
|
||||||
|
void
|
||||||
|
mem_region_init (struct mem_region *new)
|
||||||
|
{
|
||||||
|
memset (new, 0, sizeof (struct mem_region));
|
||||||
|
new->enabled_p = 1;
|
||||||
|
new->attrib = default_mem_attrib;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function should be called before any command which would
|
||||||
|
modify the memory region list. It will handle switching from
|
||||||
|
a target-provided list to a local list, if necessary. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
require_user_regions (int from_tty)
|
||||||
|
{
|
||||||
|
struct mem_region *m;
|
||||||
|
int ix, length;
|
||||||
|
|
||||||
|
/* If we're already using a user-provided list, nothing to do. */
|
||||||
|
if (!mem_use_target)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Switch to a user-provided list (possibly a copy of the current
|
||||||
|
one). */
|
||||||
|
mem_use_target = 0;
|
||||||
|
|
||||||
|
/* If we don't have a target-provided region list yet, then
|
||||||
|
no need to warn. */
|
||||||
|
if (mem_region_list == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Otherwise, let the user know how to get back. */
|
||||||
|
if (from_tty)
|
||||||
|
warning (_("Switching to manual control of memory regions; use "
|
||||||
|
"\"mem auto\" to fetch regions from the target again."));
|
||||||
|
|
||||||
|
/* And create a new list for the user to modify. */
|
||||||
|
length = VEC_length (mem_region_s, target_mem_region_list);
|
||||||
|
mem_region_list = VEC_alloc (mem_region_s, length);
|
||||||
|
for (ix = 0; VEC_iterate (mem_region_s, target_mem_region_list, ix, m); ix++)
|
||||||
|
VEC_quick_push (mem_region_s, mem_region_list, m);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function should be called before any command which would
|
||||||
|
read the memory region list, other than those which call
|
||||||
|
require_user_regions. It will handle fetching the
|
||||||
|
target-provided list, if necessary. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
require_target_regions (void)
|
||||||
|
{
|
||||||
|
if (mem_use_target && !target_mem_regions_valid)
|
||||||
|
{
|
||||||
|
target_mem_regions_valid = 1;
|
||||||
|
target_mem_region_list = target_memory_map ();
|
||||||
|
mem_region_list = target_mem_region_list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
create_mem_region (CORE_ADDR lo, CORE_ADDR hi,
|
create_mem_region (CORE_ADDR lo, CORE_ADDR hi,
|
||||||
const struct mem_attrib *attrib)
|
const struct mem_attrib *attrib)
|
||||||
|
@ -66,6 +155,7 @@ create_mem_region (CORE_ADDR lo, CORE_ADDR hi,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mem_region_init (&new);
|
||||||
new.lo = lo;
|
new.lo = lo;
|
||||||
new.hi = hi;
|
new.hi = hi;
|
||||||
|
|
||||||
|
@ -96,7 +186,6 @@ create_mem_region (CORE_ADDR lo, CORE_ADDR hi,
|
||||||
}
|
}
|
||||||
|
|
||||||
new.number = ++mem_number;
|
new.number = ++mem_number;
|
||||||
new.enabled_p = 1;
|
|
||||||
new.attrib = *attrib;
|
new.attrib = *attrib;
|
||||||
VEC_safe_insert (mem_region_s, mem_region_list, ix, &new);
|
VEC_safe_insert (mem_region_s, mem_region_list, ix, &new);
|
||||||
}
|
}
|
||||||
|
@ -113,6 +202,8 @@ lookup_mem_region (CORE_ADDR addr)
|
||||||
CORE_ADDR hi;
|
CORE_ADDR hi;
|
||||||
int ix;
|
int ix;
|
||||||
|
|
||||||
|
require_target_regions ();
|
||||||
|
|
||||||
/* First we initialize LO and HI so that they describe the entire
|
/* First we initialize LO and HI so that they describe the entire
|
||||||
memory space. As we process the memory region chain, they are
|
memory space. As we process the memory region chain, they are
|
||||||
redefined to describe the minimal region containing ADDR. LO
|
redefined to describe the minimal region containing ADDR. LO
|
||||||
|
@ -148,6 +239,31 @@ lookup_mem_region (CORE_ADDR addr)
|
||||||
region.attrib = default_mem_attrib;
|
region.attrib = default_mem_attrib;
|
||||||
return ®ion;
|
return ®ion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Invalidate any memory regions fetched from the target. */
|
||||||
|
|
||||||
|
void
|
||||||
|
invalidate_target_mem_regions (void)
|
||||||
|
{
|
||||||
|
struct mem_region *m;
|
||||||
|
int ix;
|
||||||
|
|
||||||
|
if (!target_mem_regions_valid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
target_mem_regions_valid = 0;
|
||||||
|
VEC_free (mem_region_s, target_mem_region_list);
|
||||||
|
if (mem_use_target)
|
||||||
|
mem_region_list = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear memory region list */
|
||||||
|
|
||||||
|
static void
|
||||||
|
mem_clear (void)
|
||||||
|
{
|
||||||
|
VEC_free (mem_region_s, mem_region_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -160,6 +276,24 @@ mem_command (char *args, int from_tty)
|
||||||
if (!args)
|
if (!args)
|
||||||
error_no_arg (_("No mem"));
|
error_no_arg (_("No mem"));
|
||||||
|
|
||||||
|
/* For "mem auto", switch back to using a target provided list. */
|
||||||
|
if (strcmp (args, "auto") == 0)
|
||||||
|
{
|
||||||
|
if (mem_use_target)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (mem_region_list != target_mem_region_list)
|
||||||
|
{
|
||||||
|
mem_clear ();
|
||||||
|
mem_region_list = target_mem_region_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
mem_use_target = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
require_user_regions (from_tty);
|
||||||
|
|
||||||
tok = strtok (args, " \t");
|
tok = strtok (args, " \t");
|
||||||
if (!tok)
|
if (!tok)
|
||||||
error (_("no lo address"));
|
error (_("no lo address"));
|
||||||
|
@ -235,6 +369,13 @@ mem_info_command (char *args, int from_tty)
|
||||||
struct mem_attrib *attrib;
|
struct mem_attrib *attrib;
|
||||||
int ix;
|
int ix;
|
||||||
|
|
||||||
|
if (mem_use_target)
|
||||||
|
printf_filtered (_("Using memory regions provided by the target.\n"));
|
||||||
|
else
|
||||||
|
printf_filtered (_("Using user-defined memory regions.\n"));
|
||||||
|
|
||||||
|
require_target_regions ();
|
||||||
|
|
||||||
if (!mem_region_list)
|
if (!mem_region_list)
|
||||||
{
|
{
|
||||||
printf_unfiltered (_("There are no memory regions defined.\n"));
|
printf_unfiltered (_("There are no memory regions defined.\n"));
|
||||||
|
@ -306,6 +447,9 @@ mem_info_command (char *args, int from_tty)
|
||||||
case MEM_WO:
|
case MEM_WO:
|
||||||
printf_filtered ("wo ");
|
printf_filtered ("wo ");
|
||||||
break;
|
break;
|
||||||
|
case MEM_FLASH:
|
||||||
|
printf_filtered ("flash blocksize 0x%x ", attrib->blocksize);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (attrib->width)
|
switch (attrib->width)
|
||||||
|
@ -378,6 +522,8 @@ mem_enable_command (char *args, int from_tty)
|
||||||
struct mem_region *m;
|
struct mem_region *m;
|
||||||
int ix;
|
int ix;
|
||||||
|
|
||||||
|
require_user_regions (from_tty);
|
||||||
|
|
||||||
dcache_invalidate (target_dcache);
|
dcache_invalidate (target_dcache);
|
||||||
|
|
||||||
if (p == 0)
|
if (p == 0)
|
||||||
|
@ -430,6 +576,8 @@ mem_disable_command (char *args, int from_tty)
|
||||||
struct mem_region *m;
|
struct mem_region *m;
|
||||||
int ix;
|
int ix;
|
||||||
|
|
||||||
|
require_user_regions (from_tty);
|
||||||
|
|
||||||
dcache_invalidate (target_dcache);
|
dcache_invalidate (target_dcache);
|
||||||
|
|
||||||
if (p == 0)
|
if (p == 0)
|
||||||
|
@ -455,14 +603,6 @@ mem_disable_command (char *args, int from_tty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear memory region list */
|
|
||||||
|
|
||||||
static void
|
|
||||||
mem_clear (void)
|
|
||||||
{
|
|
||||||
VEC_free (mem_region_s, mem_region_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Delete the memory region number NUM. */
|
/* Delete the memory region number NUM. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -497,6 +637,8 @@ mem_delete_command (char *args, int from_tty)
|
||||||
char *p1;
|
char *p1;
|
||||||
int num;
|
int num;
|
||||||
|
|
||||||
|
require_user_regions (from_tty);
|
||||||
|
|
||||||
dcache_invalidate (target_dcache);
|
dcache_invalidate (target_dcache);
|
||||||
|
|
||||||
if (p == 0)
|
if (p == 0)
|
||||||
|
@ -532,8 +674,10 @@ void
|
||||||
_initialize_mem (void)
|
_initialize_mem (void)
|
||||||
{
|
{
|
||||||
add_com ("mem", class_vars, mem_command, _("\
|
add_com ("mem", class_vars, mem_command, _("\
|
||||||
Define attributes for memory region.\n\
|
Define attributes for memory region or reset memory region handling to\n\
|
||||||
Usage: mem <lo addr> <hi addr> [<mode> <width> <cache>], \n\
|
target-based.\n\
|
||||||
|
Usage: mem auto\n\
|
||||||
|
mem <lo addr> <hi addr> [<mode> <width> <cache>], \n\
|
||||||
where <mode> may be rw (read/write), ro (read-only) or wo (write-only), \n\
|
where <mode> may be rw (read/write), ro (read-only) or wo (write-only), \n\
|
||||||
<width> may be 8, 16, 32, or 64, and \n\
|
<width> may be 8, 16, 32, or 64, and \n\
|
||||||
<cache> may be cache or nocache"));
|
<cache> may be cache or nocache"));
|
||||||
|
|
|
@ -28,7 +28,10 @@ enum mem_access_mode
|
||||||
{
|
{
|
||||||
MEM_RW, /* read/write */
|
MEM_RW, /* read/write */
|
||||||
MEM_RO, /* read only */
|
MEM_RO, /* read only */
|
||||||
MEM_WO /* write only */
|
MEM_WO, /* write only */
|
||||||
|
|
||||||
|
/* Read/write, but special steps are required to write to it. */
|
||||||
|
MEM_FLASH
|
||||||
};
|
};
|
||||||
|
|
||||||
enum mem_access_width
|
enum mem_access_width
|
||||||
|
@ -66,6 +69,9 @@ struct mem_attrib
|
||||||
/* enables memory verification. after a write, memory is re-read
|
/* enables memory verification. after a write, memory is re-read
|
||||||
to verify that the write was successful. */
|
to verify that the write was successful. */
|
||||||
int verify;
|
int verify;
|
||||||
|
|
||||||
|
/* Block size. Only valid if mode == MEM_FLASH. */
|
||||||
|
int blocksize;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mem_region
|
struct mem_region
|
||||||
|
@ -91,4 +97,10 @@ DEF_VEC_O(mem_region_s);
|
||||||
|
|
||||||
extern struct mem_region *lookup_mem_region(CORE_ADDR);
|
extern struct mem_region *lookup_mem_region(CORE_ADDR);
|
||||||
|
|
||||||
|
void invalidate_target_mem_regions (void);
|
||||||
|
|
||||||
|
void mem_region_init (struct mem_region *);
|
||||||
|
|
||||||
|
int mem_region_cmp (const void *, const void *);
|
||||||
|
|
||||||
#endif /* MEMATTR_H */
|
#endif /* MEMATTR_H */
|
||||||
|
|
273
gdb/memory-map.c
Normal file
273
gdb/memory-map.c
Normal file
|
@ -0,0 +1,273 @@
|
||||||
|
/* Routines for handling XML memory maps provided by target.
|
||||||
|
|
||||||
|
Copyright (C) 2006
|
||||||
|
Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
This file is part of GDB.
|
||||||
|
|
||||||
|
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., 51 Franklin Street, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA. */
|
||||||
|
|
||||||
|
#include "defs.h"
|
||||||
|
#include "memory-map.h"
|
||||||
|
#include "gdb_assert.h"
|
||||||
|
#include "exceptions.h"
|
||||||
|
|
||||||
|
#include "gdb_string.h"
|
||||||
|
|
||||||
|
#if !defined(HAVE_LIBEXPAT)
|
||||||
|
|
||||||
|
VEC(mem_region_s) *
|
||||||
|
parse_memory_map (const char *memory_map)
|
||||||
|
{
|
||||||
|
static int have_warned;
|
||||||
|
|
||||||
|
if (!have_warned)
|
||||||
|
{
|
||||||
|
have_warned = 1;
|
||||||
|
warning (_("Can not parse XML memory map; XML support was disabled "
|
||||||
|
"at compile time"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* HAVE_LIBEXPAT */
|
||||||
|
|
||||||
|
#include "xml-support.h"
|
||||||
|
#include <expat.h>
|
||||||
|
|
||||||
|
/* Internal parsing data passed to all Expat callbacks. */
|
||||||
|
struct memory_map_parsing_data
|
||||||
|
{
|
||||||
|
VEC(mem_region_s) **memory_map;
|
||||||
|
struct mem_region *currently_parsing;
|
||||||
|
char *character_data;
|
||||||
|
const char *property_name;
|
||||||
|
int capture_text;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
free_memory_map_parsing_data (void *p_)
|
||||||
|
{
|
||||||
|
struct memory_map_parsing_data *p = p_;
|
||||||
|
|
||||||
|
xfree (p->character_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Callback called by Expat on start of element.
|
||||||
|
DATA_ is pointer to memory_map_parsing_data
|
||||||
|
NAME is the name of element
|
||||||
|
ATTRS is the zero-terminated array of attribute names and
|
||||||
|
attribute values.
|
||||||
|
|
||||||
|
This function handles the following elements:
|
||||||
|
- 'memory' -- creates a new memory region and initializes it
|
||||||
|
from attributes. Sets DATA_.currently_parsing to the new region.
|
||||||
|
- 'properties' -- sets DATA.capture_text. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
memory_map_start_element (void *data_, const XML_Char *name,
|
||||||
|
const XML_Char **attrs)
|
||||||
|
{
|
||||||
|
static const XML_Char *type_names[] = {"ram", "rom", "flash", 0};
|
||||||
|
static int type_values[] = { MEM_RW, MEM_RO, MEM_FLASH };
|
||||||
|
struct memory_map_parsing_data *data = data_;
|
||||||
|
struct gdb_exception ex;
|
||||||
|
|
||||||
|
TRY_CATCH (ex, RETURN_MASK_ERROR)
|
||||||
|
{
|
||||||
|
if (strcmp (name, "memory") == 0)
|
||||||
|
{
|
||||||
|
struct mem_region *r;
|
||||||
|
|
||||||
|
r = VEC_safe_push (mem_region_s, *data->memory_map, NULL);
|
||||||
|
mem_region_init (r);
|
||||||
|
|
||||||
|
r->lo = xml_get_integer_attribute (attrs, "start");
|
||||||
|
r->hi = r->lo + xml_get_integer_attribute (attrs, "length");
|
||||||
|
r->attrib.mode = xml_get_enum_value (attrs, "type", type_names,
|
||||||
|
type_values);
|
||||||
|
r->attrib.blocksize = -1;
|
||||||
|
|
||||||
|
data->currently_parsing = r;
|
||||||
|
}
|
||||||
|
else if (strcmp (name, "property") == 0)
|
||||||
|
{
|
||||||
|
if (!data->currently_parsing)
|
||||||
|
throw_error (XML_PARSE_ERROR,
|
||||||
|
_("memory map: found 'property' element outside 'memory'"));
|
||||||
|
|
||||||
|
data->capture_text = 1;
|
||||||
|
|
||||||
|
data->property_name = xml_get_required_attribute (attrs, "name");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ex.reason < 0)
|
||||||
|
throw_error
|
||||||
|
(ex.error, _("While parsing element %s:\n%s"), name, ex.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Callback called by Expat on start of element. DATA_ is a pointer
|
||||||
|
to our memory_map_parsing_data. NAME is the name of the element.
|
||||||
|
|
||||||
|
This function handles the following elements:
|
||||||
|
- 'property' -- check that the property name is 'blocksize' and
|
||||||
|
sets DATA->currently_parsing->attrib.blocksize
|
||||||
|
- 'memory' verifies that flash block size is set. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
memory_map_end_element (void *data_, const XML_Char *name)
|
||||||
|
{
|
||||||
|
struct memory_map_parsing_data *data = data_;
|
||||||
|
struct gdb_exception ex;
|
||||||
|
|
||||||
|
TRY_CATCH (ex, RETURN_MASK_ERROR)
|
||||||
|
{
|
||||||
|
if (strcmp (name, "property") == 0)
|
||||||
|
{
|
||||||
|
if (strcmp (data->property_name, "blocksize") == 0)
|
||||||
|
{
|
||||||
|
if (!data->character_data)
|
||||||
|
throw_error (XML_PARSE_ERROR,
|
||||||
|
_("Empty content of 'property' element"));
|
||||||
|
char *end = NULL;
|
||||||
|
data->currently_parsing->attrib.blocksize
|
||||||
|
= strtoul (data->character_data, &end, 0);
|
||||||
|
if (*end != '\0')
|
||||||
|
throw_error (XML_PARSE_ERROR,
|
||||||
|
_("Invalid content of the 'blocksize' property"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw_error (XML_PARSE_ERROR,
|
||||||
|
_("Unknown memory region property: %s"), name);
|
||||||
|
|
||||||
|
data->capture_text = 0;
|
||||||
|
}
|
||||||
|
else if (strcmp (name, "memory") == 0)
|
||||||
|
{
|
||||||
|
if (data->currently_parsing->attrib.mode == MEM_FLASH
|
||||||
|
&& data->currently_parsing->attrib.blocksize == -1)
|
||||||
|
throw_error (XML_PARSE_ERROR,
|
||||||
|
_("Flash block size is not set"));
|
||||||
|
|
||||||
|
data->currently_parsing = 0;
|
||||||
|
data->character_data = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ex.reason < 0)
|
||||||
|
throw_error
|
||||||
|
(ex.error, _("while parsing element %s: \n%s"), name, ex.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Callback called by expat for all character data blocks.
|
||||||
|
DATA_ is the pointer to memory_map_parsing_data.
|
||||||
|
S is the point to character data.
|
||||||
|
LEN is the length of data; the data is not zero-terminated.
|
||||||
|
|
||||||
|
If DATA_->CAPTURE_TEXT is 1, appends this block of characters
|
||||||
|
to DATA_->CHARACTER_DATA. */
|
||||||
|
static void
|
||||||
|
memory_map_character_data (void *data_, const XML_Char *s,
|
||||||
|
int len)
|
||||||
|
{
|
||||||
|
struct memory_map_parsing_data *data = data_;
|
||||||
|
int current_size = 0;
|
||||||
|
|
||||||
|
if (!data->capture_text)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Expat interface does not guarantee that a single call to
|
||||||
|
a handler will be made. Actually, one call for each line
|
||||||
|
will be made, and character data can possibly span several
|
||||||
|
lines.
|
||||||
|
|
||||||
|
Take care to realloc the data if needed. */
|
||||||
|
if (!data->character_data)
|
||||||
|
data->character_data = xmalloc (len + 1);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
current_size = strlen (data->character_data);
|
||||||
|
data->character_data = xrealloc (data->character_data,
|
||||||
|
current_size + len + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy (data->character_data + current_size, s, len);
|
||||||
|
data->character_data[current_size + len] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
clear_result (void *p)
|
||||||
|
{
|
||||||
|
VEC(mem_region_s) **result = p;
|
||||||
|
VEC_free (mem_region_s, *result);
|
||||||
|
*result = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
VEC(mem_region_s) *
|
||||||
|
parse_memory_map (const char *memory_map)
|
||||||
|
{
|
||||||
|
VEC(mem_region_s) *result = NULL;
|
||||||
|
struct cleanup *back_to = make_cleanup (null_cleanup, NULL);
|
||||||
|
struct cleanup *before_deleting_result;
|
||||||
|
struct cleanup *saved;
|
||||||
|
volatile struct gdb_exception ex;
|
||||||
|
int ok = 0;
|
||||||
|
|
||||||
|
struct memory_map_parsing_data data = {};
|
||||||
|
|
||||||
|
XML_Parser parser = XML_ParserCreateNS (NULL, '!');
|
||||||
|
if (parser == NULL)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
make_cleanup_free_xml_parser (parser);
|
||||||
|
make_cleanup (free_memory_map_parsing_data, &data);
|
||||||
|
/* Note: 'clear_result' will zero 'result'. */
|
||||||
|
before_deleting_result = make_cleanup (clear_result, &result);
|
||||||
|
|
||||||
|
XML_SetElementHandler (parser, memory_map_start_element,
|
||||||
|
memory_map_end_element);
|
||||||
|
XML_SetCharacterDataHandler (parser, memory_map_character_data);
|
||||||
|
XML_SetUserData (parser, &data);
|
||||||
|
data.memory_map = &result;
|
||||||
|
|
||||||
|
TRY_CATCH (ex, RETURN_MASK_ERROR)
|
||||||
|
{
|
||||||
|
if (XML_Parse (parser, memory_map, strlen (memory_map), 1)
|
||||||
|
!= XML_STATUS_OK)
|
||||||
|
{
|
||||||
|
enum XML_Error err = XML_GetErrorCode (parser);
|
||||||
|
|
||||||
|
throw_error (XML_PARSE_ERROR, "%s", XML_ErrorString (err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ex.reason != GDB_NO_ERROR)
|
||||||
|
{
|
||||||
|
if (ex.error == XML_PARSE_ERROR)
|
||||||
|
/* Just report it. */
|
||||||
|
warning (_("Could not parse XML memory map: %s"), ex.message);
|
||||||
|
else
|
||||||
|
throw_exception (ex);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
/* Parsed successfully, don't need to delete the result. */
|
||||||
|
discard_cleanups (before_deleting_result);
|
||||||
|
|
||||||
|
out:
|
||||||
|
do_cleanups (back_to);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* HAVE_LIBEXPAT */
|
34
gdb/memory-map.h
Normal file
34
gdb/memory-map.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/* Routines for handling XML memory maps provided by target.
|
||||||
|
|
||||||
|
Copyright (C) 2006
|
||||||
|
Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
This file is part of GDB.
|
||||||
|
|
||||||
|
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., 51 Franklin Street, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA. */
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef MEMORY_MAP_H
|
||||||
|
#define MEMORY_MAP_H
|
||||||
|
|
||||||
|
#include "memattr.h"
|
||||||
|
|
||||||
|
/* Parses XML memory map passed as argument and returns the memory
|
||||||
|
regions it describes. On any error, emits error message and
|
||||||
|
returns 0. Does not throw. Ownership of result is passed to the caller. */
|
||||||
|
VEC(mem_region_s) *parse_memory_map (const char *memory_map);
|
||||||
|
|
||||||
|
#endif
|
34
gdb/remote.c
34
gdb/remote.c
|
@ -60,6 +60,8 @@
|
||||||
|
|
||||||
#include "remote-fileio.h"
|
#include "remote-fileio.h"
|
||||||
|
|
||||||
|
#include "memory-map.h"
|
||||||
|
|
||||||
/* The size to align memory write packets, when practical. The protocol
|
/* The size to align memory write packets, when practical. The protocol
|
||||||
does not guarantee any alignment, and gdb will generate short
|
does not guarantee any alignment, and gdb will generate short
|
||||||
writes and unaligned writes, but even as a best-effort attempt this
|
writes and unaligned writes, but even as a best-effort attempt this
|
||||||
|
@ -826,6 +828,7 @@ enum {
|
||||||
PACKET_Z3,
|
PACKET_Z3,
|
||||||
PACKET_Z4,
|
PACKET_Z4,
|
||||||
PACKET_qXfer_auxv,
|
PACKET_qXfer_auxv,
|
||||||
|
PACKET_qXfer_memory_map,
|
||||||
PACKET_qGetTLSAddr,
|
PACKET_qGetTLSAddr,
|
||||||
PACKET_qSupported,
|
PACKET_qSupported,
|
||||||
PACKET_MAX
|
PACKET_MAX
|
||||||
|
@ -2172,7 +2175,9 @@ remote_packet_size (const struct protocol_feature *feature,
|
||||||
static struct protocol_feature remote_protocol_features[] = {
|
static struct protocol_feature remote_protocol_features[] = {
|
||||||
{ "PacketSize", PACKET_DISABLE, remote_packet_size, -1 },
|
{ "PacketSize", PACKET_DISABLE, remote_packet_size, -1 },
|
||||||
{ "qXfer:auxv:read", PACKET_DISABLE, remote_supported_packet,
|
{ "qXfer:auxv:read", PACKET_DISABLE, remote_supported_packet,
|
||||||
PACKET_qXfer_auxv }
|
PACKET_qXfer_auxv },
|
||||||
|
{ "qXfer:memory-map:read", PACKET_DISABLE, remote_supported_packet,
|
||||||
|
PACKET_qXfer_memory_map }
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -5312,6 +5317,11 @@ remote_xfer_partial (struct target_ops *ops, enum target_object object,
|
||||||
return remote_read_qxfer (ops, "auxv", annex, readbuf, offset, len,
|
return remote_read_qxfer (ops, "auxv", annex, readbuf, offset, len,
|
||||||
&remote_protocol_packets[PACKET_qXfer_auxv]);
|
&remote_protocol_packets[PACKET_qXfer_auxv]);
|
||||||
|
|
||||||
|
case TARGET_OBJECT_MEMORY_MAP:
|
||||||
|
gdb_assert (annex == NULL);
|
||||||
|
return remote_read_qxfer (ops, "memory-map", annex, readbuf, offset, len,
|
||||||
|
&remote_protocol_packets[PACKET_qXfer_memory_map]);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -5422,6 +5432,23 @@ remote_rcmd (char *command,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static VEC(mem_region_s) *
|
||||||
|
remote_memory_map (struct target_ops *ops)
|
||||||
|
{
|
||||||
|
VEC(mem_region_s) *result = NULL;
|
||||||
|
char *text = target_read_stralloc (¤t_target,
|
||||||
|
TARGET_OBJECT_MEMORY_MAP, NULL);
|
||||||
|
|
||||||
|
if (text)
|
||||||
|
{
|
||||||
|
struct cleanup *back_to = make_cleanup (xfree, text);
|
||||||
|
result = parse_memory_map (text);
|
||||||
|
do_cleanups (back_to);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
packet_command (char *args, int from_tty)
|
packet_command (char *args, int from_tty)
|
||||||
{
|
{
|
||||||
|
@ -5694,6 +5721,7 @@ Specify the serial device it is connected to\n\
|
||||||
remote_ops.to_has_execution = 1;
|
remote_ops.to_has_execution = 1;
|
||||||
remote_ops.to_has_thread_control = tc_schedlock; /* can lock scheduler */
|
remote_ops.to_has_thread_control = tc_schedlock; /* can lock scheduler */
|
||||||
remote_ops.to_magic = OPS_MAGIC;
|
remote_ops.to_magic = OPS_MAGIC;
|
||||||
|
remote_ops.to_memory_map = remote_memory_map;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set up the extended remote vector by making a copy of the standard
|
/* Set up the extended remote vector by making a copy of the standard
|
||||||
|
@ -5823,6 +5851,7 @@ Specify the serial device it is connected to (e.g. /dev/ttya).";
|
||||||
remote_async_ops.to_async = remote_async;
|
remote_async_ops.to_async = remote_async;
|
||||||
remote_async_ops.to_async_mask_value = 1;
|
remote_async_ops.to_async_mask_value = 1;
|
||||||
remote_async_ops.to_magic = OPS_MAGIC;
|
remote_async_ops.to_magic = OPS_MAGIC;
|
||||||
|
remote_async_ops.to_memory_map = remote_memory_map;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set up the async extended remote vector by making a copy of the standard
|
/* Set up the async extended remote vector by making a copy of the standard
|
||||||
|
@ -6063,6 +6092,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
|
||||||
add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_auxv],
|
add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_auxv],
|
||||||
"qXfer:auxv:read", "read-aux-vector", 0);
|
"qXfer:auxv:read", "read-aux-vector", 0);
|
||||||
|
|
||||||
|
add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_memory_map],
|
||||||
|
"qXfer:memory-map:read", "memory-map", 0);
|
||||||
|
|
||||||
add_packet_config_cmd (&remote_protocol_packets[PACKET_qGetTLSAddr],
|
add_packet_config_cmd (&remote_protocol_packets[PACKET_qGetTLSAddr],
|
||||||
"qGetTLSAddr", "get-thread-local-storage-address",
|
"qGetTLSAddr", "get-thread-local-storage-address",
|
||||||
0);
|
0);
|
||||||
|
|
63
gdb/target.c
63
gdb/target.c
|
@ -464,6 +464,7 @@ update_current_target (void)
|
||||||
INHERIT (to_make_corefile_notes, t);
|
INHERIT (to_make_corefile_notes, t);
|
||||||
INHERIT (to_get_thread_local_address, t);
|
INHERIT (to_get_thread_local_address, t);
|
||||||
INHERIT (to_magic, t);
|
INHERIT (to_magic, t);
|
||||||
|
/* Do not inherit to_memory_map. */
|
||||||
}
|
}
|
||||||
#undef INHERIT
|
#undef INHERIT
|
||||||
|
|
||||||
|
@ -1040,6 +1041,54 @@ target_write_memory (CORE_ADDR memaddr, const gdb_byte *myaddr, int len)
|
||||||
return EIO;
|
return EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Fetch the target's memory map. */
|
||||||
|
|
||||||
|
VEC(mem_region_s) *
|
||||||
|
target_memory_map (void)
|
||||||
|
{
|
||||||
|
VEC(mem_region_s) *result;
|
||||||
|
struct mem_region *last_one, *this_one;
|
||||||
|
int ix;
|
||||||
|
struct target_ops *t;
|
||||||
|
|
||||||
|
if (targetdebug)
|
||||||
|
fprintf_unfiltered (gdb_stdlog, "target_memory_map ()\n");
|
||||||
|
|
||||||
|
for (t = current_target.beneath; t != NULL; t = t->beneath)
|
||||||
|
if (t->to_memory_map != NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (t == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
result = t->to_memory_map (t);
|
||||||
|
if (result == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
qsort (VEC_address (mem_region_s, result),
|
||||||
|
VEC_length (mem_region_s, result),
|
||||||
|
sizeof (struct mem_region), mem_region_cmp);
|
||||||
|
|
||||||
|
/* Check that regions do not overlap. Simultaneously assign
|
||||||
|
a numbering for the "mem" commands to use to refer to
|
||||||
|
each region. */
|
||||||
|
last_one = NULL;
|
||||||
|
for (ix = 0; VEC_iterate (mem_region_s, result, ix, this_one); ix++)
|
||||||
|
{
|
||||||
|
this_one->number = ix;
|
||||||
|
|
||||||
|
if (last_one && last_one->hi > this_one->lo)
|
||||||
|
{
|
||||||
|
warning (_("Overlapping regions in memory map: ignoring"));
|
||||||
|
VEC_free (mem_region_s, result);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
last_one = this_one;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef target_stopped_data_address_p
|
#ifndef target_stopped_data_address_p
|
||||||
int
|
int
|
||||||
target_stopped_data_address_p (struct target_ops *target)
|
target_stopped_data_address_p (struct target_ops *target)
|
||||||
|
@ -1356,6 +1405,18 @@ target_info (char *args, int from_tty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This function is called before any new inferior is created, e.g.
|
||||||
|
by running a program, attaching, or connecting to a target.
|
||||||
|
It cleans up any state from previous invocations which might
|
||||||
|
change between runs. This is a subset of what target_preopen
|
||||||
|
resets (things which might change between targets). */
|
||||||
|
|
||||||
|
void
|
||||||
|
target_pre_inferior (int from_tty)
|
||||||
|
{
|
||||||
|
invalidate_target_mem_regions ();
|
||||||
|
}
|
||||||
|
|
||||||
/* This is to be called by the open routine before it does
|
/* This is to be called by the open routine before it does
|
||||||
anything. */
|
anything. */
|
||||||
|
|
||||||
|
@ -1378,6 +1439,8 @@ target_preopen (int from_tty)
|
||||||
|
|
||||||
if (target_has_execution)
|
if (target_has_execution)
|
||||||
pop_target ();
|
pop_target ();
|
||||||
|
|
||||||
|
target_pre_inferior (from_tty);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Detach a target after doing deferred register stores. */
|
/* Detach a target after doing deferred register stores. */
|
||||||
|
|
27
gdb/target.h
27
gdb/target.h
|
@ -55,6 +55,7 @@ struct bp_target_info;
|
||||||
#include "symtab.h"
|
#include "symtab.h"
|
||||||
#include "dcache.h"
|
#include "dcache.h"
|
||||||
#include "memattr.h"
|
#include "memattr.h"
|
||||||
|
#include "vec.h"
|
||||||
|
|
||||||
enum strata
|
enum strata
|
||||||
{
|
{
|
||||||
|
@ -198,7 +199,9 @@ enum target_object
|
||||||
/* Transfer auxilliary vector. */
|
/* Transfer auxilliary vector. */
|
||||||
TARGET_OBJECT_AUXV,
|
TARGET_OBJECT_AUXV,
|
||||||
/* StackGhost cookie. See "sparc-tdep.c". */
|
/* StackGhost cookie. See "sparc-tdep.c". */
|
||||||
TARGET_OBJECT_WCOOKIE
|
TARGET_OBJECT_WCOOKIE,
|
||||||
|
/* Target memory map in XML format. */
|
||||||
|
TARGET_OBJECT_MEMORY_MAP,
|
||||||
|
|
||||||
/* Possible future objects: TARGET_OBJECT_FILE, TARGET_OBJECT_PROC, ... */
|
/* Possible future objects: TARGET_OBJECT_FILE, TARGET_OBJECT_PROC, ... */
|
||||||
};
|
};
|
||||||
|
@ -453,6 +456,21 @@ struct target_ops
|
||||||
gdb_byte *readbuf, const gdb_byte *writebuf,
|
gdb_byte *readbuf, const gdb_byte *writebuf,
|
||||||
ULONGEST offset, LONGEST len);
|
ULONGEST offset, LONGEST len);
|
||||||
|
|
||||||
|
/* Returns the memory map for the target. A return value of NULL
|
||||||
|
means that no memory map is available. If a memory address
|
||||||
|
does not fall within any returned regions, it's assumed to be
|
||||||
|
RAM. The returned memory regions should not overlap.
|
||||||
|
|
||||||
|
The order of regions does not matter; target_memory_map will
|
||||||
|
sort regions by starting address. For that reason, this
|
||||||
|
function should not be called directly except via
|
||||||
|
target_memory_map.
|
||||||
|
|
||||||
|
This method should not cache data; if the memory map could
|
||||||
|
change unexpectedly, it should be invalidated, and higher
|
||||||
|
layers will re-fetch it. */
|
||||||
|
VEC(mem_region_s) *(*to_memory_map) (struct target_ops *);
|
||||||
|
|
||||||
int to_magic;
|
int to_magic;
|
||||||
/* Need sub-structure for target machine related rather than comm related?
|
/* Need sub-structure for target machine related rather than comm related?
|
||||||
*/
|
*/
|
||||||
|
@ -576,6 +594,11 @@ extern int xfer_memory (CORE_ADDR, gdb_byte *, int, int,
|
||||||
extern int child_xfer_memory (CORE_ADDR, gdb_byte *, int, int,
|
extern int child_xfer_memory (CORE_ADDR, gdb_byte *, int, int,
|
||||||
struct mem_attrib *, struct target_ops *);
|
struct mem_attrib *, struct target_ops *);
|
||||||
|
|
||||||
|
/* Fetches the target's memory map. If one is found it is sorted
|
||||||
|
and returned, after some consistency checking. Otherwise, NULL
|
||||||
|
is returned. */
|
||||||
|
VEC(mem_region_s) *target_memory_map (void);
|
||||||
|
|
||||||
extern char *child_pid_to_exec_file (int);
|
extern char *child_pid_to_exec_file (int);
|
||||||
|
|
||||||
extern char *child_core_file_to_sym_file (char *);
|
extern char *child_core_file_to_sym_file (char *);
|
||||||
|
@ -1127,6 +1150,8 @@ extern int push_target (struct target_ops *);
|
||||||
|
|
||||||
extern int unpush_target (struct target_ops *);
|
extern int unpush_target (struct target_ops *);
|
||||||
|
|
||||||
|
extern void target_pre_inferior (int);
|
||||||
|
|
||||||
extern void target_preopen (int);
|
extern void target_preopen (int);
|
||||||
|
|
||||||
extern void pop_target (void);
|
extern void pop_target (void);
|
||||||
|
|
146
gdb/xml-support.c
Normal file
146
gdb/xml-support.c
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
/* Helper routines for parsing XML using Expat.
|
||||||
|
|
||||||
|
Copyright (C) 2006
|
||||||
|
Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
This file is part of GDB.
|
||||||
|
|
||||||
|
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., 51 Franklin Street, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA. */
|
||||||
|
|
||||||
|
#include "defs.h"
|
||||||
|
|
||||||
|
/* The contents of this file are only useful if XML support is
|
||||||
|
available. */
|
||||||
|
#ifdef HAVE_LIBEXPAT
|
||||||
|
|
||||||
|
#include "exceptions.h"
|
||||||
|
#include "xml-support.h"
|
||||||
|
|
||||||
|
#include <expat.h>
|
||||||
|
|
||||||
|
#include "gdb_string.h"
|
||||||
|
|
||||||
|
/* Returns the value of attribute ATTR from expat attribute list
|
||||||
|
ATTRLIST. If not found, throws an exception. */
|
||||||
|
|
||||||
|
const XML_Char *
|
||||||
|
xml_get_required_attribute (const XML_Char **attrs,
|
||||||
|
const XML_Char *attr)
|
||||||
|
{
|
||||||
|
const XML_Char **p;
|
||||||
|
for (p = attrs; *p; p += 2)
|
||||||
|
{
|
||||||
|
const char *name = p[0];
|
||||||
|
const char *val = p[1];
|
||||||
|
|
||||||
|
if (strcmp (name, attr) == 0)
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
throw_error (XML_PARSE_ERROR, _("Can't find attribute %s"), attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse a field VALSTR that we expect to contain an integer value.
|
||||||
|
The integer is returned in *VALP. The string is parsed with an
|
||||||
|
equivalent to strtoul.
|
||||||
|
|
||||||
|
Returns 0 for success, -1 for error. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
xml_parse_unsigned_integer (const char *valstr, ULONGEST *valp)
|
||||||
|
{
|
||||||
|
const char *endptr;
|
||||||
|
ULONGEST result;
|
||||||
|
|
||||||
|
if (*valstr == '\0')
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
result = strtoulst (valstr, &endptr, 0);
|
||||||
|
if (*endptr != '\0')
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
*valp = result;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Gets the value of an integer attribute named ATTR, if it's present.
|
||||||
|
If the attribute is not found, or can't be parsed as integer,
|
||||||
|
throws an exception. */
|
||||||
|
|
||||||
|
ULONGEST
|
||||||
|
xml_get_integer_attribute (const XML_Char **attrs,
|
||||||
|
const XML_Char *attr)
|
||||||
|
{
|
||||||
|
ULONGEST result;
|
||||||
|
const XML_Char *value = xml_get_required_attribute (attrs, attr);
|
||||||
|
|
||||||
|
if (xml_parse_unsigned_integer (value, &result) != 0)
|
||||||
|
{
|
||||||
|
throw_error (XML_PARSE_ERROR,
|
||||||
|
_("Can't convert value of attribute %s, %s, to integer"),
|
||||||
|
attr, value);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Obtains a value of attribute with enumerated type. In XML, enumerated
|
||||||
|
attributes have string as a value, and in C, they are represented as
|
||||||
|
values of enumerated type. This function maps the attribute onto
|
||||||
|
an integer value that can be immediately converted into enumerated
|
||||||
|
type.
|
||||||
|
|
||||||
|
First, obtains the string value of ATTR in ATTRS.
|
||||||
|
Then, finds the index of that value in XML_NAMES, which is a zero-terminated
|
||||||
|
array of strings. If found, returns the element of VALUES with that index.
|
||||||
|
Otherwise throws. */
|
||||||
|
|
||||||
|
int
|
||||||
|
xml_get_enum_value (const XML_Char **attrs,
|
||||||
|
const XML_Char *attr,
|
||||||
|
const XML_Char **xml_names,
|
||||||
|
int *values)
|
||||||
|
{
|
||||||
|
const XML_Char *value = xml_get_required_attribute (attrs, attr);
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i = 0; xml_names[i]; ++i)
|
||||||
|
{
|
||||||
|
if (strcmp (xml_names[i], value) == 0)
|
||||||
|
return values[i];
|
||||||
|
}
|
||||||
|
throw_error (XML_PARSE_ERROR,
|
||||||
|
_("Invalid enumerated value in XML: %s"), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cleanup wrapper for XML_ParserFree, with the correct type
|
||||||
|
for make_cleanup. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
free_xml_parser (void *parser)
|
||||||
|
{
|
||||||
|
XML_ParserFree (parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Register a cleanup to release PARSER. Only the parser itself
|
||||||
|
is freed; another cleanup may be necessary to discard any
|
||||||
|
associated user data. */
|
||||||
|
|
||||||
|
void
|
||||||
|
make_cleanup_free_xml_parser (XML_Parser parser)
|
||||||
|
{
|
||||||
|
make_cleanup (free_xml_parser, parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* HAVE_LIBEXPAT */
|
45
gdb/xml-support.h
Normal file
45
gdb/xml-support.h
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
/* Helper routines for parsing XML using Expat.
|
||||||
|
|
||||||
|
Copyright (C) 2006
|
||||||
|
Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
This file is part of GDB.
|
||||||
|
|
||||||
|
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., 51 Franklin Street, Fifth Floor,
|
||||||
|
Boston, MA 02110-1301, USA. */
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef XML_SUPPORT_H
|
||||||
|
#define XML_SUPPORT_H
|
||||||
|
|
||||||
|
#include <expat.h>
|
||||||
|
|
||||||
|
/* Helper functions for parsing XML documents. See xml-support.c
|
||||||
|
for more information about these functions. */
|
||||||
|
|
||||||
|
const XML_Char *xml_get_required_attribute (const XML_Char **attrs,
|
||||||
|
const XML_Char *attr);
|
||||||
|
|
||||||
|
ULONGEST xml_get_integer_attribute (const XML_Char **attrs,
|
||||||
|
const XML_Char *attr);
|
||||||
|
|
||||||
|
int xml_get_enum_value (const XML_Char **attrs,
|
||||||
|
const XML_Char *attr,
|
||||||
|
const XML_Char **xml_names,
|
||||||
|
int *values);
|
||||||
|
|
||||||
|
void make_cleanup_free_xml_parser (XML_Parser parser);
|
||||||
|
|
||||||
|
#endif
|
Loading…
Add table
Add a link
Reference in a new issue