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