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