/ deps / KittyMemoryEx / KittyMemoryEx.hpp
KittyMemoryEx.hpp
  1  #pragma once
  2  
  3  #include "KittyUtils.hpp"
  4  #include <unordered_map>
  5  
  6  /**
  7   * @brief Provides utility functions for process memory.
  8   */
  9  namespace KittyMemoryEx
 10  {
 11      /**
 12       * @brief Represents a mapping of a memory region.
 13       */
 14      class ProcMap
 15      {
 16      public:
 17          pid_t pid;
 18          uintptr_t startAddress;
 19          uintptr_t endAddress;
 20          size_t length;
 21          int protection;
 22          bool readable, writeable, executable;
 23          bool is_private, is_shared;
 24          bool is_ro, is_rw, is_rx;
 25          uintptr_t offset;
 26          std::string dev;
 27          unsigned long inode;
 28          std::string pathname;
 29  
 30          ProcMap()
 31              : pid(0), startAddress(0), endAddress(0), length(0), protection(0), readable(false), writeable(false),
 32                executable(false), is_private(false), is_shared(false), is_ro(false), is_rw(false), is_rx(false),
 33                offset(0), inode(0)
 34          {
 35          }
 36  
 37          inline bool operator==(const ProcMap &other) const
 38          {
 39              return (pid == other.pid && startAddress == other.startAddress && endAddress == other.endAddress &&
 40                      protection == other.protection && is_private == other.is_private && is_shared == other.is_shared &&
 41                      offset == other.offset && dev == other.dev && inode == other.inode && pathname == other.pathname);
 42          }
 43  
 44          inline bool operator!=(const ProcMap &other) const
 45          {
 46              return (pid != other.pid || startAddress != other.startAddress || endAddress != other.endAddress ||
 47                      protection != other.protection || is_private != other.is_private || is_shared != other.is_shared ||
 48                      offset != other.offset || dev != other.dev || inode != other.inode || pathname != other.pathname);
 49          }
 50  
 51          /**
 52           * @brief Checks if the map is valid.
 53           */
 54          inline bool isValid() const
 55          {
 56              return (startAddress && endAddress && length);
 57          }
 58  
 59          /**
 60           * @brief Checks if the map is unknown (i.e., no pathname).
 61           */
 62          inline bool isUnknown() const
 63          {
 64              return pathname.empty();
 65          }
 66  
 67          /**
 68           * @brief Checks if the map contains a specific address.
 69           *
 70           * @param address Address to check.
 71           * @return True if the address is within the map, false otherwise.
 72           */
 73          inline bool contains(uintptr_t address) const
 74          {
 75              return address >= startAddress && address < endAddress;
 76          }
 77  
 78          /**
 79           * @brief Converts the map to a string representation..
 80           */
 81          inline std::string toString() const
 82          {
 83              return KittyUtils::String::fmt("%" PRIxPTR "-%" PRIxPTR " %c%c%c%c %" PRIxPTR " %s %lu %s",
 84                                             startAddress,
 85                                             endAddress,
 86                                             readable ? 'r' : '-',
 87                                             writeable ? 'w' : '-',
 88                                             executable ? 'x' : '-',
 89                                             is_private ? 'p' : 's',
 90                                             offset,
 91                                             dev.c_str(),
 92                                             inode,
 93                                             pathname.c_str());
 94          }
 95      };
 96  
 97      /**
 98       * @brief Retrieves the name of the process by its process ID.
 99       *
100       * This function reads the command line of the process identified by the given process ID and returns
101       * the process name.
102       *
103       * @param pid The process ID of the process.
104       * @return The name of the process.
105       */
106      std::string getProcessName(pid_t pid);
107  
108      /**
109       * @brief Retrieves a list of process IDs that match a given process name.
110       *
111       * This function searches for all processes whose command line matches the specified process name
112       * and returns their process IDs in a vector.
113       *
114       * @param processName The name of the process to match.
115       * @return A vector of process IDs that match the specified process name.
116       */
117      std::vector<pid_t> getProcessIDs(const std::string &processName);
118  
119      /**
120       * @brief Retrieves the process ID that matches a given process name.
121       *
122       * This function searches for the first process whose command line matches the specified process name
123       * and returns its process ID.
124       *
125       * @param processName The name of the process to match.
126       * @return The process ID that matches the specified process name.
127       */
128      pid_t getProcessID(const std::string &processName);
129  
130      /**
131       * @brief Retrieves a list of thread IDs for a given process ID.
132       *
133       * This function retrieves the thread IDs of all threads associated with the specified process ID
134       * by examining the `/proc/[pid]/task` directory.
135       *
136       * @param pid The process ID of the process.
137       * @return A vector of thread IDs for the specified process.
138       */
139      std::vector<pid_t> getAllThreads(pid_t pid);
140  
141      /**
142       * @brief Class to retrieve process status information.
143       */
144      class ProcStatus
145      {
146          pid_t _pid, _tid;
147          std::unordered_map<std::string, std::string> data;
148          static bool parse(const std::string &path, ProcStatus *out);
149  
150      public:
151          ProcStatus() : _pid(-1), _tid(-1)
152          {
153          }
154          ~ProcStatus()
155          {
156              data.clear();
157          }
158  
159          /**
160           * @brief Parses the status of a process given its PID.
161           *
162           * @param pid The PID of the process to parse.
163           * @param out A pointer to the ProcStatus object where the parsed data will be stored.
164           * @return True if parsing was successful, false otherwise.
165           */
166          inline static bool parse(pid_t pid, ProcStatus *out)
167          {
168              if (pid <= 0 || !out)
169                  return false;
170  
171              out->_pid = pid;
172              return parse("/proc/" + std::to_string(pid) + "/status", out);
173          }
174  
175          /**
176           * @brief Parses the status of a process given its PID and thread ID.
177           *
178           * @param pid The PID of the process.
179           * @param tid The thread ID of the process.
180           * @param out A pointer to the ProcStatus object where the parsed data will be stored.
181           * @return True if parsing was successful, false otherwise.
182           */
183          inline static bool parse(pid_t pid, pid_t tid, ProcStatus *out)
184          {
185              if (pid <= 0 || tid <= 0 || !out)
186                  return false;
187  
188              out->_pid = pid;
189              out->_tid = tid;
190              return parse("/proc/" + std::to_string(pid) + "/task/" + std::to_string(tid) + "/status", out);
191          }
192  
193          /**
194           * @brief Refreshes the process status.
195           *
196           * If the tid is less than or equal to 0, it calls the parse function with the pid.
197           * If the tid is greater than 0, it calls the parse function with the pid and tid.
198           *
199           * @return True if refreshing was successful, false otherwise.
200           */
201          inline bool refresh()
202          {
203              return _tid <= 0 ? parse(_pid, this) : parse(_pid, _tid, this);
204          }
205  
206          /**
207           * @brief Checks if the process status data contains a specific key.
208           *
209           * @param key The key to check.
210           * @return True if the key exists, false otherwise.
211           */
212          inline bool contains(const std::string &key) const
213          {
214              return data.find(key) != data.end();
215          }
216  
217          /**
218           * @brief Retrieves the string value associated with a key.
219           *
220           * @param key The key to retrieve.
221           * @return The string value associated with the key, or an empty string if the key is not found.
222           */
223          inline std::string getString(const std::string &key) const
224          {
225              auto it = data.find(key);
226              return (it != data.end()) ? it->second : "";
227          }
228  
229          /**
230           * @brief Retrieves the integer value associated with a key.
231           *
232           * @param key The key to retrieve.
233           * @return The integer value associated with the key, or 0 if the key is not found.
234           */
235          inline long long getInt(const std::string &key) const
236          {
237              auto it = data.find(key);
238              if (it == data.end())
239                  return 0;
240  
241              return std::strtoll(it->second.c_str(), nullptr, 10);
242          }
243  
244          /**
245           * @brief Retrieves the boolean value associated with a key.
246           *
247           * @param key The key to retrieve.
248           * @return True if the key's value is 1, false otherwise.
249           */
250          inline bool getBool(const std::string &key) const
251          {
252              return getInt(key) == 1;
253          }
254      };
255  
256      /**
257       * @brief Enumerates the filter types for finding memory maps.
258       */
259      enum class EProcMapFilter
260      {
261          Equal,
262          Contains,
263          StartWith,
264          EndWith,
265          Regex
266      };
267  
268      /**
269       * @brief Retrieves information about all memory maps in a remote process.
270       *
271       * @param pid The remote process ID
272       * @return Vector of ProcMap objects representing all memory maps.
273       */
274      std::vector<ProcMap> getAllMaps(pid_t pid);
275  
276      /**
277       * @brief Retrieves information about all memory maps in a remote process.
278       *
279       * @param pid The remote process ID
280       * @param filter Filter type to use.
281       * @param name Name to filter by.
282       * @param maps The vector of cached process maps (optional).
283       * @return Vector of ProcMap objects that match the filter.
284       */
285      std::vector<ProcMap> getMaps(pid_t pid,
286                                   EProcMapFilter filter,
287                                   const std::string &name,
288                                   const std::vector<ProcMap> &maps = std::vector<ProcMap>());
289  
290      /**
291       * @brief Retrieves the map information for a specific address in the current process.
292       *
293       * @param pid The remote process ID
294       * @param address Address to search for.
295       * @param maps The vector of cached process maps (optional).
296       * @return ProcMap object representing the map for the address, or an invalid map if not found.
297       */
298      ProcMap getAddressMap(pid_t pid, uintptr_t address, const std::vector<ProcMap> &maps = std::vector<ProcMap>());
299  
300  #ifdef __ANDROID__
301      /**
302       * @brief Retrieves the Android app directory.
303       *
304       * @param pkg The app's package name
305       * @return App directory
306       */
307      std::string getAppDirectory(const std::string &pkg);
308  #endif
309  } // namespace KittyMemoryEx