X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fprologue-value.h;h=99feffe8e4b0637ccb63606836c8701be34a7824;hb=refs%2Fheads%2Fconcurrent-displaced-stepping-2020-04-01;hp=ec44cad021f052cf7a7bee034302ce6818c248e6;hpb=01f0fe5e0450edf168c1f612feb93cf588e4e7ea;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/prologue-value.h b/gdb/prologue-value.h index ec44cad021..99feffe8e4 100644 --- a/gdb/prologue-value.h +++ b/gdb/prologue-value.h @@ -1,11 +1,11 @@ /* Interface to prologue value handling for GDB. - Copyright 2003, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2003-2020 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 + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -14,16 +14,32 @@ 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: - - Free Software Foundation, Inc. - 51 Franklin St - Fifth Floor - Boston, MA 02110-1301 - USA */ + along with this program. If not, see . */ #ifndef PROLOGUE_VALUE_H #define PROLOGUE_VALUE_H +/* What sort of value is this? This determines the interpretation + of subsequent fields. */ +enum prologue_value_kind +{ + /* We don't know anything about the value. This is also used for + values we could have kept track of, when doing so would have + been too complex and we don't want to bother. The bottom of + our lattice. */ + pvk_unknown, + + /* A known constant. K is its value. */ + pvk_constant, + + /* The value that register REG originally had *UPON ENTRY TO THE + FUNCTION*, plus K. If K is zero, this means, obviously, just + the value REG had upon entry to the function. REG is a GDB + register number. Before we start interpreting, we initialize + every register R to { pvk_register, R, 0 }. */ + pvk_register, +}; + /* When we analyze a prologue, we're really doing 'abstract interpretation' or 'pseudo-evaluation': running the function's code in simulation, but using conservative approximations of the values @@ -105,7 +121,7 @@ understand and maintain. In the approach used here: - It's easier to see that the analyzer is correct: you just see - whether the analyzer properly (albiet conservatively) simulates + whether the analyzer properly (albeit conservatively) simulates the effect of each instruction. - It's easier to extend the analyzer: you can add support for new @@ -125,25 +141,7 @@ struct prologue_value { /* What sort of value is this? This determines the interpretation of subsequent fields. */ - enum { - - /* We don't know anything about the value. This is also used for - values we could have kept track of, when doing so would have - been too complex and we don't want to bother. The bottom of - our lattice. */ - pvk_unknown, - - /* A known constant. K is its value. */ - pvk_constant, - - /* The value that register REG originally had *UPON ENTRY TO THE - FUNCTION*, plus K. If K is zero, this means, obviously, just - the value REG had upon entry to the function. REG is a GDB - register number. Before we start interpreting, we initialize - every register R to { pvk_register, R, 0 }. */ - pvk_register, - - } kind; + enum prologue_value_kind kind; /* The meanings of the following fields depend on 'kind'; see the comments for the specific 'kind' values. */ @@ -223,80 +221,110 @@ enum pv_boolean pv_is_array_ref (pv_t addr, CORE_ADDR size, int *i); -/* A 'struct pv_area' keeps track of values stored in a particular - region of memory. */ -struct pv_area; +/* A 'pv_area' keeps track of values stored in a particular region of + memory. */ +class pv_area +{ +public: -/* Create a new area, tracking stores relative to the original value - of BASE_REG. If BASE_REG is SP, then this effectively records the - contents of the stack frame: the original value of the SP is the - frame's CFA, or some constant offset from it. + /* Create a new area, tracking stores relative to the original value + of BASE_REG. If BASE_REG is SP, then this effectively records the + contents of the stack frame: the original value of the SP is the + frame's CFA, or some constant offset from it. - Stores to constant addresses, unknown addresses, or to addresses - relative to registers other than BASE_REG will trash this area; see - pv_area_store_would_trash. */ -struct pv_area *make_pv_area (int base_reg); + Stores to constant addresses, unknown addresses, or to addresses + relative to registers other than BASE_REG will trash this area; see + pv_area::store_would_trash. -/* Free AREA. */ -void free_pv_area (struct pv_area *area); + To check whether a pointer refers to this area, only the low + ADDR_BIT bits will be compared. */ + pv_area (int base_reg, int addr_bit); + ~pv_area (); -/* Register a cleanup to free AREA. */ -struct cleanup *make_cleanup_free_pv_area (struct pv_area *area); + DISABLE_COPY_AND_ASSIGN (pv_area); + /* Store the SIZE-byte value VALUE at ADDR in AREA. -/* Store the SIZE-byte value VALUE at ADDR in AREA. + If ADDR is not relative to the same base register we used in + creating AREA, then we can't tell which values here the stored + value might overlap, and we'll have to mark everything as + unknown. */ + void store (pv_t addr, + CORE_ADDR size, + pv_t value); - If ADDR is not relative to the same base register we used in - creating AREA, then we can't tell which values here the stored - value might overlap, and we'll have to mark everything as - unknown. */ -void pv_area_store (struct pv_area *area, - pv_t addr, - CORE_ADDR size, - pv_t value); + /* Return the SIZE-byte value at ADDR in AREA. This may return + pv_unknown (). */ + pv_t fetch (pv_t addr, CORE_ADDR size); -/* Return the SIZE-byte value at ADDR in AREA. This may return - pv_unknown (). */ -pv_t pv_area_fetch (struct pv_area *area, pv_t addr, CORE_ADDR size); + /* Return true if storing to address ADDR in AREA would force us to + mark the contents of the entire area as unknown. This could happen + if, say, ADDR is unknown, since we could be storing anywhere. Or, + it could happen if ADDR is relative to a different register than + the other stores base register, since we don't know the relative + values of the two registers. -/* Return true if storing to address ADDR in AREA would force us to - mark the contents of the entire area as unknown. This could happen - if, say, ADDR is unknown, since we could be storing anywhere. Or, - it could happen if ADDR is relative to a different register than - the other stores base register, since we don't know the relative - values of the two registers. + If you've reached such a store, it may be better to simply stop the + prologue analysis, and return the information you've gathered, + instead of losing all that information, most of which is probably + okay. */ + bool store_would_trash (pv_t addr); - If you've reached such a store, it may be better to simply stop the - prologue analysis, and return the information you've gathered, - instead of losing all that information, most of which is probably - okay. */ -int pv_area_store_would_trash (struct pv_area *area, pv_t addr); + /* Search AREA for the original value of REGISTER. If we can't find + it, return zero; if we can find it, return a non-zero value, and if + OFFSET_P is non-zero, set *OFFSET_P to the register's offset within + AREA. GDBARCH is the architecture of which REGISTER is a member. + In the worst case, this takes time proportional to the number of + items stored in AREA. If you plan to gather a lot of information + about registers saved in AREA, consider calling pv_area::scan + instead, and collecting all your information in one pass. */ + bool find_reg (struct gdbarch *gdbarch, int reg, CORE_ADDR *offset_p); -/* Search AREA for the original value of REGISTER. If we can't find - it, return zero; if we can find it, return a non-zero value, and if - OFFSET_P is non-zero, set *OFFSET_P to the register's offset within - AREA. GDBARCH is the architecture of which REGISTER is a member. - In the worst case, this takes time proportional to the number of - items stored in AREA. If you plan to gather a lot of information - about registers saved in AREA, consider calling pv_area_scan - instead, and collecting all your information in one pass. */ -int pv_area_find_reg (struct pv_area *area, - struct gdbarch *gdbarch, - int register, - CORE_ADDR *offset_p); + /* For every part of AREA whose value we know, apply FUNC to CLOSURE, + the value's address, its size, and the value itself. */ + void scan (void (*func) (void *closure, + pv_t addr, + CORE_ADDR size, + pv_t value), + void *closure); +private: -/* For every part of AREA whose value we know, apply FUNC to CLOSURE, - the value's address, its size, and the value itself. */ -void pv_area_scan (struct pv_area *area, - void (*func) (void *closure, - pv_t addr, - CORE_ADDR size, - pv_t value), - void *closure); + struct area_entry; + /* Delete all entries from AREA. */ + void clear_entries (); + + /* Return a pointer to the first entry we hit in AREA starting at + OFFSET and going forward. + + This may return zero, if AREA has no entries. + + And since the entries are a ring, this may return an entry that + entirely precedes OFFSET. This is the correct behavior: depending + on the sizes involved, we could still overlap such an area, with + wrap-around. */ + struct area_entry *find_entry (CORE_ADDR offset); + + /* Return non-zero if the SIZE bytes at OFFSET would overlap ENTRY; + return zero otherwise. AREA is the area to which ENTRY belongs. */ + int overlaps (struct area_entry *entry, + CORE_ADDR offset, + CORE_ADDR size); + + /* This area's base register. */ + int m_base_reg; + + /* The mask to apply to addresses, to make the wrap-around happen at + the right place. */ + CORE_ADDR m_addr_mask; + + /* An element of the doubly-linked ring of entries, or zero if we + have none. */ + struct area_entry *m_entry; +}; #endif /* PROLOGUE_VALUE_H */