xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/frame-info.h (revision 6881a4007f077b54e5f51159c52b9b25f57deb0d)
1*6881a400Schristos /* Frame info pointer
2*6881a400Schristos 
3*6881a400Schristos    Copyright (C) 2022-2023 Free Software Foundation, Inc.
4*6881a400Schristos 
5*6881a400Schristos    This file is part of GDB.
6*6881a400Schristos 
7*6881a400Schristos    This program is free software; you can redistribute it and/or modify
8*6881a400Schristos    it under the terms of the GNU General Public License as published by
9*6881a400Schristos    the Free Software Foundation; either version 3 of the License, or
10*6881a400Schristos    (at your option) any later version.
11*6881a400Schristos 
12*6881a400Schristos    This program is distributed in the hope that it will be useful,
13*6881a400Schristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
14*6881a400Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15*6881a400Schristos    GNU General Public License for more details.
16*6881a400Schristos 
17*6881a400Schristos    You should have received a copy of the GNU General Public License
18*6881a400Schristos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19*6881a400Schristos 
20*6881a400Schristos #ifndef GDB_FRAME_INFO_H
21*6881a400Schristos #define GDB_FRAME_INFO_H
22*6881a400Schristos 
23*6881a400Schristos #include "gdbsupport/intrusive_list.h"
24*6881a400Schristos #include "frame-id.h"
25*6881a400Schristos 
26*6881a400Schristos struct frame_info;
27*6881a400Schristos 
28*6881a400Schristos /* A wrapper for "frame_info *".  frame_info objects are invalidated
29*6881a400Schristos    whenever reinit_frame_cache is called.  This class arranges to
30*6881a400Schristos    invalidate the pointer when appropriate.  This is done to help
31*6881a400Schristos    detect a GDB bug that was relatively common.
32*6881a400Schristos 
33*6881a400Schristos    A small amount of code must still operate on raw pointers, so a
34*6881a400Schristos    "get" method is provided.  However, you should normally not use
35*6881a400Schristos    this in new code.  */
36*6881a400Schristos 
37*6881a400Schristos class frame_info_ptr : public intrusive_list_node<frame_info_ptr>
38*6881a400Schristos {
39*6881a400Schristos public:
40*6881a400Schristos   /* Create a frame_info_ptr from a raw pointer.  */
41*6881a400Schristos   explicit frame_info_ptr (struct frame_info *ptr)
42*6881a400Schristos     : m_ptr (ptr)
43*6881a400Schristos   {
44*6881a400Schristos     frame_list.push_back (*this);
45*6881a400Schristos   }
46*6881a400Schristos 
47*6881a400Schristos   /* Create a null frame_info_ptr.  */
48*6881a400Schristos   frame_info_ptr ()
49*6881a400Schristos   {
50*6881a400Schristos     frame_list.push_back (*this);
51*6881a400Schristos   }
52*6881a400Schristos 
53*6881a400Schristos   frame_info_ptr (std::nullptr_t)
54*6881a400Schristos   {
55*6881a400Schristos     frame_list.push_back (*this);
56*6881a400Schristos   }
57*6881a400Schristos 
58*6881a400Schristos   frame_info_ptr (const frame_info_ptr &other)
59*6881a400Schristos     : m_ptr (other.m_ptr),
60*6881a400Schristos       m_cached_id (other.m_cached_id),
61*6881a400Schristos       m_cached_level (other.m_cached_level)
62*6881a400Schristos   {
63*6881a400Schristos     frame_list.push_back (*this);
64*6881a400Schristos   }
65*6881a400Schristos 
66*6881a400Schristos   frame_info_ptr (frame_info_ptr &&other)
67*6881a400Schristos     : m_ptr (other.m_ptr),
68*6881a400Schristos       m_cached_id (other.m_cached_id),
69*6881a400Schristos       m_cached_level (other.m_cached_level)
70*6881a400Schristos   {
71*6881a400Schristos     other.m_ptr = nullptr;
72*6881a400Schristos     other.m_cached_id = null_frame_id;
73*6881a400Schristos     other.m_cached_level = invalid_level;
74*6881a400Schristos     frame_list.push_back (*this);
75*6881a400Schristos   }
76*6881a400Schristos 
77*6881a400Schristos   ~frame_info_ptr ()
78*6881a400Schristos   {
79*6881a400Schristos     /* If this node has static storage, it may be deleted after
80*6881a400Schristos        frame_list.  Attempting to erase ourselves would then trigger
81*6881a400Schristos        internal errors, so make sure we are still linked first.  */
82*6881a400Schristos     if (is_linked ())
83*6881a400Schristos       frame_list.erase (frame_list.iterator_to (*this));
84*6881a400Schristos   }
85*6881a400Schristos 
86*6881a400Schristos   frame_info_ptr &operator= (const frame_info_ptr &other)
87*6881a400Schristos   {
88*6881a400Schristos     m_ptr = other.m_ptr;
89*6881a400Schristos     m_cached_id = other.m_cached_id;
90*6881a400Schristos     m_cached_level = other.m_cached_level;
91*6881a400Schristos     return *this;
92*6881a400Schristos   }
93*6881a400Schristos 
94*6881a400Schristos   frame_info_ptr &operator= (std::nullptr_t)
95*6881a400Schristos   {
96*6881a400Schristos     m_ptr = nullptr;
97*6881a400Schristos     m_cached_id = null_frame_id;
98*6881a400Schristos     m_cached_level = invalid_level;
99*6881a400Schristos     return *this;
100*6881a400Schristos   }
101*6881a400Schristos 
102*6881a400Schristos   frame_info_ptr &operator= (frame_info_ptr &&other)
103*6881a400Schristos   {
104*6881a400Schristos     m_ptr = other.m_ptr;
105*6881a400Schristos     m_cached_id = other.m_cached_id;
106*6881a400Schristos     m_cached_level = other.m_cached_level;
107*6881a400Schristos     other.m_ptr = nullptr;
108*6881a400Schristos     other.m_cached_id = null_frame_id;
109*6881a400Schristos     other.m_cached_level = invalid_level;
110*6881a400Schristos     return *this;
111*6881a400Schristos   }
112*6881a400Schristos 
113*6881a400Schristos   frame_info *operator-> () const
114*6881a400Schristos   {
115*6881a400Schristos     return m_ptr;
116*6881a400Schristos   }
117*6881a400Schristos 
118*6881a400Schristos   /* Fetch the underlying pointer.  Note that new code should
119*6881a400Schristos      generally not use this -- avoid it if at all possible.  */
120*6881a400Schristos   frame_info *get () const
121*6881a400Schristos   {
122*6881a400Schristos     return m_ptr;
123*6881a400Schristos   }
124*6881a400Schristos 
125*6881a400Schristos   /* This exists for compatibility with pre-existing code that checked
126*6881a400Schristos      a "frame_info *" using "!".  */
127*6881a400Schristos   bool operator! () const
128*6881a400Schristos   {
129*6881a400Schristos     return m_ptr == nullptr;
130*6881a400Schristos   }
131*6881a400Schristos 
132*6881a400Schristos   /* This exists for compatibility with pre-existing code that checked
133*6881a400Schristos      a "frame_info *" like "if (ptr)".  */
134*6881a400Schristos   explicit operator bool () const
135*6881a400Schristos   {
136*6881a400Schristos     return m_ptr != nullptr;
137*6881a400Schristos   }
138*6881a400Schristos 
139*6881a400Schristos   /* Invalidate this pointer.  */
140*6881a400Schristos   void invalidate ()
141*6881a400Schristos   {
142*6881a400Schristos     m_ptr = nullptr;
143*6881a400Schristos   }
144*6881a400Schristos 
145*6881a400Schristos   /* Cache the frame_id that the pointer will use to reinflate.  */
146*6881a400Schristos   void prepare_reinflate ();
147*6881a400Schristos 
148*6881a400Schristos   /* Use the cached frame_id to reinflate the pointer.  */
149*6881a400Schristos   void reinflate ();
150*6881a400Schristos 
151*6881a400Schristos private:
152*6881a400Schristos   /* We sometimes need to construct frame_info_ptr objects around the
153*6881a400Schristos      sentinel_frame, which has level -1.  Therefore, make the invalid frame
154*6881a400Schristos      level value -2.  */
155*6881a400Schristos   static constexpr int invalid_level = -2;
156*6881a400Schristos 
157*6881a400Schristos   /* The underlying pointer.  */
158*6881a400Schristos   frame_info *m_ptr = nullptr;
159*6881a400Schristos 
160*6881a400Schristos   /* The frame_id of the underlying pointer.  */
161*6881a400Schristos   frame_id m_cached_id = null_frame_id;
162*6881a400Schristos 
163*6881a400Schristos   /* The frame level of the underlying pointer.  */
164*6881a400Schristos   int m_cached_level = invalid_level;
165*6881a400Schristos 
166*6881a400Schristos   /* All frame_info_ptr objects are kept on an intrusive list.
167*6881a400Schristos      This keeps their construction and destruction costs
168*6881a400Schristos      reasonably small.  */
169*6881a400Schristos   static intrusive_list<frame_info_ptr> frame_list;
170*6881a400Schristos 
171*6881a400Schristos   /* A friend so it can invalidate the pointers.  */
172*6881a400Schristos   friend void reinit_frame_cache ();
173*6881a400Schristos };
174*6881a400Schristos 
175*6881a400Schristos static inline bool
176*6881a400Schristos operator== (const frame_info *self, const frame_info_ptr &other)
177*6881a400Schristos {
178*6881a400Schristos   return self == other.get ();
179*6881a400Schristos }
180*6881a400Schristos 
181*6881a400Schristos static inline bool
182*6881a400Schristos operator== (const frame_info_ptr &self, const frame_info_ptr &other)
183*6881a400Schristos {
184*6881a400Schristos   return self.get () == other.get ();
185*6881a400Schristos }
186*6881a400Schristos 
187*6881a400Schristos static inline bool
188*6881a400Schristos operator== (const frame_info_ptr &self, const frame_info *other)
189*6881a400Schristos {
190*6881a400Schristos   return self.get () == other;
191*6881a400Schristos }
192*6881a400Schristos 
193*6881a400Schristos static inline bool
194*6881a400Schristos operator!= (const frame_info *self, const frame_info_ptr &other)
195*6881a400Schristos {
196*6881a400Schristos   return self != other.get ();
197*6881a400Schristos }
198*6881a400Schristos 
199*6881a400Schristos static inline bool
200*6881a400Schristos operator!= (const frame_info_ptr &self, const frame_info_ptr &other)
201*6881a400Schristos {
202*6881a400Schristos   return self.get () != other.get ();
203*6881a400Schristos }
204*6881a400Schristos 
205*6881a400Schristos static inline bool
206*6881a400Schristos operator!= (const frame_info_ptr &self, const frame_info *other)
207*6881a400Schristos {
208*6881a400Schristos   return self.get () != other;
209*6881a400Schristos }
210*6881a400Schristos 
211*6881a400Schristos #endif /* GDB_FRAME_INFO_H */
212