GDB (xrefs)
Loading...
Searching...
No Matches
memattr.c
Go to the documentation of this file.
1/* Memory attributes support, for GDB.
2
3 Copyright (C) 2001-2023 Free Software Foundation, Inc.
4
5 This file is part of GDB.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19
20#include "defs.h"
21#include "command.h"
22#include "gdbcmd.h"
23#include "memattr.h"
24#include "target.h"
25#include "target-dcache.h"
26#include "value.h"
27#include "language.h"
28#include "breakpoint.h"
29#include "cli/cli-utils.h"
30#include <algorithm>
31#include "gdbarch.h"
32
33static std::vector<mem_region> user_mem_region_list, target_mem_region_list;
34static std::vector<mem_region> *mem_region_list = &target_mem_region_list;
35static int mem_number = 0;
36
37/* If this flag is set, the memory region list should be automatically
38 updated from the target. If it is clear, the list is user-controlled
39 and should be left alone. */
40
41static bool
46
47/* If this flag is set, we have tried to fetch the target memory regions
48 since the last time it was invalidated. If that list is still
49 empty, then the target can't supply memory regions. */
51
52/* If this flag is set, gdb will assume that memory ranges not
53 specified by the memory map have type MEM_NONE, and will
54 emit errors on all accesses to that memory. */
55static bool inaccessible_by_default = true;
56
57static void
58show_inaccessible_by_default (struct ui_file *file, int from_tty,
59 struct cmd_list_element *c,
60 const char *value)
61{
63 gdb_printf (file, _("Unknown memory addresses will "
64 "be treated as inaccessible.\n"));
65 else
66 gdb_printf (file, _("Unknown memory addresses "
67 "will be treated as RAM.\n"));
68}
69
70/* This function should be called before any command which would
71 modify the memory region list. It will handle switching from
72 a target-provided list to a local list, if necessary. */
73
74static void
76{
77 /* If we're already using a user-provided list, nothing to do. */
78 if (!mem_use_target ())
79 return;
80
81 /* Switch to a user-provided list (possibly a copy of the current
82 one). */
84
85 /* If we don't have a target-provided region list yet, then
86 no need to warn. */
87 if (target_mem_region_list.empty ())
88 return;
89
90 /* Otherwise, let the user know how to get back. */
91 if (from_tty)
92 warning (_("Switching to manual control of memory regions; use "
93 "\"mem auto\" to fetch regions from the target again."));
94
95 /* And create a new list (copy of the target-supplied regions) for the user
96 to modify. */
98}
99
100/* This function should be called before any command which would
101 read the memory region list, other than those which call
102 require_user_regions. It will handle fetching the
103 target-provided list, if necessary. */
104
105static void
114
115/* Create a new user-defined memory region. */
116
117static void
118create_user_mem_region (CORE_ADDR lo, CORE_ADDR hi,
119 const mem_attrib &attrib)
120{
121 /* lo == hi is a useless empty region. */
122 if (lo >= hi && hi != 0)
123 {
124 gdb_printf (_("invalid memory region: low >= high\n"));
125 return;
126 }
127
128 mem_region newobj (lo, hi, attrib);
129
130 auto it = std::lower_bound (user_mem_region_list.begin (),
132 newobj);
133 int ix = std::distance (user_mem_region_list.begin (), it);
134
135 /* Check for an overlapping memory region. We only need to check
136 in the vincinity - at most one before and one after the
137 insertion point. */
138 for (int i = ix - 1; i < ix + 1; i++)
139 {
140 if (i < 0)
141 continue;
142 if (i >= user_mem_region_list.size ())
143 continue;
144
146
147 if ((lo >= n.lo && (lo < n.hi || n.hi == 0))
148 || (hi > n.lo && (hi <= n.hi || n.hi == 0))
149 || (lo <= n.lo && ((hi >= n.hi && n.hi != 0) || hi == 0)))
150 {
151 gdb_printf (_("overlapping memory region\n"));
152 return;
153 }
154 }
155
156 newobj.number = ++mem_number;
157 user_mem_region_list.insert (it, newobj);
158}
159
160/* Look up the memory region corresponding to ADDR. */
161
162struct mem_region *
163lookup_mem_region (CORE_ADDR addr)
164{
165 static struct mem_region region (0, 0);
166 CORE_ADDR lo;
167 CORE_ADDR hi;
168
170
171 /* First we initialize LO and HI so that they describe the entire
172 memory space. As we process the memory region chain, they are
173 redefined to describe the minimal region containing ADDR. LO
174 and HI are used in the case where no memory region is defined
175 that contains ADDR. If a memory region is disabled, it is
176 treated as if it does not exist. The initial values for LO
177 and HI represent the bottom and top of memory. */
178
179 lo = 0;
180 hi = 0;
181
182 /* Either find memory range containing ADDR, or set LO and HI
183 to the nearest boundaries of an existing memory range.
184
185 If we ever want to support a huge list of memory regions, this
186 check should be replaced with a binary search (probably using
187 VEC_lower_bound). */
188 for (mem_region &m : *mem_region_list)
189 {
190 if (m.enabled_p == 1)
191 {
192 /* If the address is in the memory region, return that
193 memory range. */
194 if (addr >= m.lo && (addr < m.hi || m.hi == 0))
195 return &m;
196
197 /* This (correctly) won't match if m->hi == 0, representing
198 the top of the address space, because CORE_ADDR is unsigned;
199 no value of LO is less than zero. */
200 if (addr >= m.hi && lo < m.hi)
201 lo = m.hi;
202
203 /* This will never set HI to zero; if we're here and ADDR
204 is at or below M, and the region starts at zero, then ADDR
205 would have been in the region. */
206 if (addr <= m.lo && (hi == 0 || hi > m.lo))
207 hi = m.lo;
208 }
209 }
210
211 /* Because no region was found, we must cons up one based on what
212 was learned above. */
213 region.lo = lo;
214 region.hi = hi;
215
216 /* When no memory map is defined at all, we always return
217 'default_mem_attrib', so that we do not make all memory
218 inaccessible for targets that don't provide a memory map. */
220 region.attrib = mem_attrib::unknown ();
221 else
222 region.attrib = mem_attrib ();
223
224 return &region;
225}
226
227/* Invalidate any memory regions fetched from the target. */
228
229void
231{
233 return;
234
236 target_mem_region_list.clear ();
237}
238
239/* Clear user-defined memory region list. */
240
241static void
243{
244 user_mem_region_list.clear ();
245}
246
247
248static void
249mem_command (const char *args, int from_tty)
250{
251 CORE_ADDR lo, hi;
252
253 if (!args)
254 error_no_arg (_("No mem"));
255
256 /* For "mem auto", switch back to using a target provided list. */
257 if (strcmp (args, "auto") == 0)
258 {
259 if (mem_use_target ())
260 return;
261
264
265 return;
266 }
267
268 require_user_regions (from_tty);
269
270 std::string tok = extract_arg (&args);
271 if (tok == "")
272 error (_("no lo address"));
273 lo = parse_and_eval_address (tok.c_str ());
274
275 tok = extract_arg (&args);
276 if (tok == "")
277 error (_("no hi address"));
278 hi = parse_and_eval_address (tok.c_str ());
279
281 while ((tok = extract_arg (&args)) != "")
282 {
283 if (tok == "rw")
285 else if (tok == "ro")
287 else if (tok == "wo")
289
290 else if (tok == "8")
292 else if (tok == "16")
293 {
294 if ((lo % 2 != 0) || (hi % 2 != 0))
295 error (_("region bounds not 16 bit aligned"));
297 }
298 else if (tok == "32")
299 {
300 if ((lo % 4 != 0) || (hi % 4 != 0))
301 error (_("region bounds not 32 bit aligned"));
303 }
304 else if (tok == "64")
305 {
306 if ((lo % 8 != 0) || (hi % 8 != 0))
307 error (_("region bounds not 64 bit aligned"));
309 }
310
311#if 0
312 else if (tok == "hwbreak")
313 attrib.hwbreak = 1;
314 else if (tok == "swbreak")
315 attrib.hwbreak = 0;
316#endif
317
318 else if (tok == "cache")
319 attrib.cache = 1;
320 else if (tok == "nocache")
321 attrib.cache = 0;
322
323#if 0
324 else if (tok == "verify")
325 attrib.verify = 1;
326 else if (tok == "noverify")
327 attrib.verify = 0;
328#endif
329
330 else
331 error (_("unknown attribute: %s"), tok.c_str ());
332 }
333
335}
336
337
338static void
339info_mem_command (const char *args, int from_tty)
340{
341 if (mem_use_target ())
342 gdb_printf (_("Using memory regions provided by the target.\n"));
343 else
344 gdb_printf (_("Using user-defined memory regions.\n"));
345
347
348 if (mem_region_list->empty ())
349 {
350 gdb_printf (_("There are no memory regions defined.\n"));
351 return;
352 }
353
354 gdb_printf ("Num ");
355 gdb_printf ("Enb ");
356 gdb_printf ("Low Addr ");
357 if (gdbarch_addr_bit (target_gdbarch ()) > 32)
358 gdb_printf (" ");
359 gdb_printf ("High Addr ");
360 if (gdbarch_addr_bit (target_gdbarch ()) > 32)
361 gdb_printf (" ");
362 gdb_printf ("Attrs ");
363 gdb_printf ("\n");
364
365 for (const mem_region &m : *mem_region_list)
366 {
367 const char *tmp;
368
369 gdb_printf ("%-3d %-3c\t",
370 m.number,
371 m.enabled_p ? 'y' : 'n');
372 if (gdbarch_addr_bit (target_gdbarch ()) <= 32)
373 tmp = hex_string_custom (m.lo, 8);
374 else
375 tmp = hex_string_custom (m.lo, 16);
376
377 gdb_printf ("%s ", tmp);
378
379 if (gdbarch_addr_bit (target_gdbarch ()) <= 32)
380 {
381 if (m.hi == 0)
382 tmp = "0x100000000";
383 else
384 tmp = hex_string_custom (m.hi, 8);
385 }
386 else
387 {
388 if (m.hi == 0)
389 tmp = "0x10000000000000000";
390 else
391 tmp = hex_string_custom (m.hi, 16);
392 }
393
394 gdb_printf ("%s ", tmp);
395
396 /* Print a token for each attribute.
397
398 * FIXME: Should we output a comma after each token? It may
399 * make it easier for users to read, but we'd lose the ability
400 * to cut-and-paste the list of attributes when defining a new
401 * region. Perhaps that is not important.
402 *
403 * FIXME: If more attributes are added to GDB, the output may
404 * become cluttered and difficult for users to read. At that
405 * time, we may want to consider printing tokens only if they
406 * are different from the default attribute. */
407
408 switch (m.attrib.mode)
409 {
410 case MEM_RW:
411 gdb_printf ("rw ");
412 break;
413 case MEM_RO:
414 gdb_printf ("ro ");
415 break;
416 case MEM_WO:
417 gdb_printf ("wo ");
418 break;
419 case MEM_FLASH:
420 gdb_printf ("flash blocksize 0x%x ", m.attrib.blocksize);
421 break;
422 }
423
424 switch (m.attrib.width)
425 {
426 case MEM_WIDTH_8:
427 gdb_printf ("8 ");
428 break;
429 case MEM_WIDTH_16:
430 gdb_printf ("16 ");
431 break;
432 case MEM_WIDTH_32:
433 gdb_printf ("32 ");
434 break;
435 case MEM_WIDTH_64:
436 gdb_printf ("64 ");
437 break;
439 break;
440 }
441
442#if 0
443 if (attrib->hwbreak)
444 gdb_printf ("hwbreak");
445 else
446 gdb_printf ("swbreak");
447#endif
448
449 if (m.attrib.cache)
450 gdb_printf ("cache ");
451 else
452 gdb_printf ("nocache ");
453
454#if 0
455 if (attrib->verify)
456 gdb_printf ("verify ");
457 else
458 gdb_printf ("noverify ");
459#endif
460
461 gdb_printf ("\n");
462 }
463}
464
465
466/* Enable the memory region number NUM. */
467
468static void
469mem_enable (int num)
470{
471 for (mem_region &m : *mem_region_list)
472 if (m.number == num)
473 {
474 m.enabled_p = 1;
475 return;
476 }
477 gdb_printf (_("No memory region number %d.\n"), num);
478}
479
480static void
481enable_mem_command (const char *args, int from_tty)
482{
483 require_user_regions (from_tty);
484
486
487 if (args == NULL || *args == '\0')
488 { /* Enable all mem regions. */
489 for (mem_region &m : *mem_region_list)
490 m.enabled_p = 1;
491 }
492 else
493 {
494 number_or_range_parser parser (args);
495 while (!parser.finished ())
496 {
497 int num = parser.get_number ();
498 mem_enable (num);
499 }
500 }
501}
502
503
504/* Disable the memory region number NUM. */
505
506static void
507mem_disable (int num)
508{
509 for (mem_region &m : *mem_region_list)
510 if (m.number == num)
511 {
512 m.enabled_p = 0;
513 return;
514 }
515 gdb_printf (_("No memory region number %d.\n"), num);
516}
517
518static void
519disable_mem_command (const char *args, int from_tty)
520{
521 require_user_regions (from_tty);
522
524
525 if (args == NULL || *args == '\0')
526 {
527 for (mem_region &m : *mem_region_list)
528 m.enabled_p = false;
529 }
530 else
531 {
532 number_or_range_parser parser (args);
533 while (!parser.finished ())
534 {
535 int num = parser.get_number ();
536 mem_disable (num);
537 }
538 }
539}
540
541/* Delete the memory region number NUM. */
542
543static void
544mem_delete (int num)
545{
546 if (!mem_region_list)
547 {
548 gdb_printf (_("No memory region number %d.\n"), num);
549 return;
550 }
551
552 auto it = std::remove_if (mem_region_list->begin (), mem_region_list->end (),
553 [num] (const mem_region &m)
554 {
555 return m.number == num;
556 });
557
558 if (it != mem_region_list->end ())
559 mem_region_list->erase (it);
560 else
561 gdb_printf (_("No memory region number %d.\n"), num);
562}
563
564static void
565delete_mem_command (const char *args, int from_tty)
566{
567 require_user_regions (from_tty);
568
570
571 if (args == NULL || *args == '\0')
572 {
573 if (query (_("Delete all memory regions? ")))
575 dont_repeat ();
576 return;
577 }
578
579 number_or_range_parser parser (args);
580 while (!parser.finished ())
581 {
582 int num = parser.get_number ();
583 mem_delete (num);
584 }
585
586 dont_repeat ();
587}
588
591
592void _initialize_mem ();
593void
595{
596 add_com ("mem", class_vars, mem_command, _("\
597Define attributes for memory region or reset memory region handling to "
598"target-based.\n\
599Usage: mem auto\n\
600 mem LOW HIGH [MODE WIDTH CACHE],\n\
601where MODE may be rw (read/write), ro (read-only) or wo (write-only),\n\
602 WIDTH may be 8, 16, 32, or 64, and\n\
603 CACHE may be cache or nocache"));
604
606Enable memory region.\n\
607Arguments are the IDs of the memory regions to enable.\n\
608Usage: enable mem [ID]...\n\
609Do \"info mem\" to see current list of IDs."), &enablelist);
610
612Disable memory region.\n\
613Arguments are the IDs of the memory regions to disable.\n\
614Usage: disable mem [ID]...\n\
615Do \"info mem\" to see current list of IDs."), &disablelist);
616
618Delete memory region.\n\
619Arguments are the IDs of the memory regions to delete.\n\
620Usage: delete mem [ID]...\n\
621Do \"info mem\" to see current list of IDs."), &deletelist);
622
624 _("Memory region attributes."));
625
627 _("Memory regions settings."),
628 _("Memory regions settings."),
630 &setlist, &showlist);
631
632 add_setshow_boolean_cmd ("inaccessible-by-default", no_class,
634Set handling of unknown memory regions."), _("\
635Show handling of unknown memory regions."), _("\
636If on, and some memory map is defined, debugger will emit errors on\n\
637accesses to memory not defined in the memory map. If off, accesses to all\n\
638memory addresses will be allowed."),
639 NULL,
643}
struct gdbarch * target_gdbarch(void)
bool finished() const
Definition cli-utils.c:327
struct cmd_list_element * showlist
Definition cli-cmds.c:127
struct cmd_list_element * deletelist
Definition cli-cmds.c:107
void error_no_arg(const char *why)
Definition cli-cmds.c:206
struct cmd_list_element * setlist
Definition cli-cmds.c:119
struct cmd_list_element * disablelist
Definition cli-cmds.c:99
struct cmd_list_element * enablelist
Definition cli-cmds.c:95
struct cmd_list_element * add_cmd(const char *name, enum command_class theclass, const char *doc, struct cmd_list_element **list)
Definition cli-decode.c:233
struct cmd_list_element * add_com(const char *name, enum command_class theclass, cmd_simple_func_ftype *fun, const char *doc)
set_show_commands add_setshow_prefix_cmd(const char *name, command_class theclass, const char *set_doc, const char *show_doc, cmd_list_element **set_subcommands_list, cmd_list_element **show_subcommands_list, cmd_list_element **set_list, cmd_list_element **show_list)
Definition cli-decode.c:428
set_show_commands add_setshow_boolean_cmd(const char *name, enum command_class theclass, bool *var, const char *set_doc, const char *show_doc, const char *help_doc, cmd_func_ftype *set_func, show_value_ftype *show_func, struct cmd_list_element **set_list, struct cmd_list_element **show_list)
Definition cli-decode.c:809
struct cmd_list_element * add_info(const char *name, cmd_simple_func_ftype *fun, const char *doc)
std::string extract_arg(const char **arg)
Definition cli-utils.c:383
void dont_repeat()
Definition top.c:696
@ class_vars
Definition command.h:55
@ no_class
Definition command.h:53
CORE_ADDR parse_and_eval_address(const char *exp)
Definition eval.c:52
int gdbarch_addr_bit(struct gdbarch *gdbarch)
Definition gdbarch.c:1739
static void enable_mem_command(const char *args, int from_tty)
Definition memattr.c:481
static void require_target_regions(void)
Definition memattr.c:106
struct mem_region * lookup_mem_region(CORE_ADDR addr)
Definition memattr.c:163
static void delete_mem_command(const char *args, int from_tty)
Definition memattr.c:565
static bool target_mem_regions_valid
Definition memattr.c:50
static void user_mem_clear(void)
Definition memattr.c:242
static void mem_command(const char *args, int from_tty)
Definition memattr.c:249
static std::vector< mem_region > * mem_region_list
Definition memattr.c:34
static std::vector< mem_region > target_mem_region_list
Definition memattr.c:33
static int mem_number
Definition memattr.c:35
static void show_inaccessible_by_default(struct ui_file *file, int from_tty, struct cmd_list_element *c, const char *value)
Definition memattr.c:58
void _initialize_mem()
Definition memattr.c:594
static std::vector< mem_region > user_mem_region_list
Definition memattr.c:33
static void disable_mem_command(const char *args, int from_tty)
Definition memattr.c:519
static struct cmd_list_element * mem_show_cmdlist
Definition memattr.c:590
static void mem_enable(int num)
Definition memattr.c:469
static void mem_delete(int num)
Definition memattr.c:544
static bool inaccessible_by_default
Definition memattr.c:55
static void mem_disable(int num)
Definition memattr.c:507
static void info_mem_command(const char *args, int from_tty)
Definition memattr.c:339
static struct cmd_list_element * mem_set_cmdlist
Definition memattr.c:589
void invalidate_target_mem_regions(void)
Definition memattr.c:230
static void create_user_mem_region(CORE_ADDR lo, CORE_ADDR hi, const mem_attrib &attrib)
Definition memattr.c:118
static void require_user_regions(int from_tty)
Definition memattr.c:75
static bool mem_use_target()
Definition memattr.c:42
@ MEM_FLASH
Definition memattr.h:31
@ MEM_RW
Definition memattr.h:26
@ MEM_WO
Definition memattr.h:28
@ MEM_RO
Definition memattr.h:27
@ MEM_WIDTH_32
Definition memattr.h:39
@ MEM_WIDTH_64
Definition memattr.h:40
@ MEM_WIDTH_16
Definition memattr.h:38
@ MEM_WIDTH_UNSPECIFIED
Definition memattr.h:36
@ MEM_WIDTH_8
Definition memattr.h:37
int hwbreak
Definition memattr.h:70
enum mem_access_mode mode
Definition memattr.h:65
static mem_attrib unknown()
Definition memattr.h:55
enum mem_access_width width
Definition memattr.h:67
int cache
Definition memattr.h:73
int verify
Definition memattr.h:77
CORE_ADDR hi
Definition memattr.h:115
CORE_ADDR lo
Definition memattr.h:112
int number
Definition memattr.h:118
mem_attrib attrib
Definition memattr.h:125
Definition value.h:130
void target_dcache_invalidate(void)
std::vector< mem_region > target_memory_map(void)
Definition target.c:1891
int query(const char *ctlstr,...)
Definition utils.c:943
void gdb_printf(struct ui_file *stream, const char *format,...)
Definition utils.c:1886