#include "lldb/lldb-public.h"
#include <functional>
-namespace lldb_utility {
+namespace lldb_private {
-//----------------------------------------------------------------------
-// Templated class that guarantees that a cleanup callback function will
-// be called. The cleanup function will be called once under the
-// following conditions:
-// - when the object goes out of scope
-// - when the user explicitly calls clean.
-// - the current value will be cleaned up when a new value is set using
-// set(T value) as long as the current value hasn't already been cleaned.
-//
-// This class is designed to be used with simple types for type T (like
-// file descriptors, opaque handles, pointers, etc). If more complex
-// type T objects are desired, we need to probably specialize this class
-// to take "const T&" for all input T parameters. Yet if a type T is
-// complex already it might be better to build the cleanup functionality
-// into T.
-//
-// The cleanup function must take one argument that is of type T.
-// The calback function return type is R. The return value is currently
-// needed for "CallbackType". If there is an easy way to get around the
-// need for the return value we can change this class.
-//
-// The two template parameters are:
-// T - The variable type of value that will be stored and used as the
-// sole argument for the cleanup callback.
-// R - The return type for the cleanup function.
-//
-// EXAMPLES
-// // Use with file handles that get opened where you want to close
-// // them. Below we use "int open(const char *path, int oflag, ...)"
-// // which returns an integer file descriptor. -1 is the invalid file
-// // descriptor so to make an object that will call "int close(int fd)"
-// // automatically we can use:
-//
-// CleanUp <int, int> fd(open("/tmp/a.txt", O_RDONLY, 0), -1, close);
-//
-// // malloc/free example
-// CleanUp <void *, void> malloced_bytes(malloc(32), NULL, free);
-//----------------------------------------------------------------------
-template <typename T, typename R = void> class CleanUp {
-public:
- typedef T value_type;
- typedef std::function<R(value_type)> CallbackType;
-
- //----------------------------------------------------------------------
- // Constructor that sets the current value only. No values are
- // considered to be invalid and the cleanup function will be called
- // regardless of the value of m_current_value.
- //----------------------------------------------------------------------
- CleanUp(value_type value, CallbackType callback)
- : m_current_value(value), m_invalid_value(), m_callback(callback),
- m_callback_called(false), m_invalid_value_is_valid(false) {}
-
- //----------------------------------------------------------------------
- // Constructor that sets the current value and also the invalid value.
- // The cleanup function will be called on "m_value" as long as it isn't
- // equal to "m_invalid_value".
- //----------------------------------------------------------------------
- CleanUp(value_type value, value_type invalid, CallbackType callback)
- : m_current_value(value), m_invalid_value(invalid), m_callback(callback),
- m_callback_called(false), m_invalid_value_is_valid(true) {}
-
- //----------------------------------------------------------------------
- // Automatically cleanup when this object goes out of scope.
- //----------------------------------------------------------------------
- ~CleanUp() { clean(); }
-
- //----------------------------------------------------------------------
- // Access the value stored in this class
- //----------------------------------------------------------------------
- value_type get() { return m_current_value; }
-
- //----------------------------------------------------------------------
- // Access the value stored in this class
- //----------------------------------------------------------------------
- const value_type get() const { return m_current_value; }
-
- //----------------------------------------------------------------------
- // Reset the owned value to "value". If a current value is valid and
- // the cleanup callback hasn't been called, the previous value will
- // be cleaned up (see void CleanUp::clean()).
- //----------------------------------------------------------------------
- void set(const value_type value) {
- // Cleanup the current value if needed
- clean();
- // Now set the new value and mark our callback as not called
- m_callback_called = false;
- m_current_value = value;
- }
-
- //----------------------------------------------------------------------
- // Checks is "m_current_value" is valid. The value is considered valid
- // no invalid value was supplied during construction of this object or
- // if an invalid value was supplied and "m_current_value" is not equal
- // to "m_invalid_value".
- //
- // Returns true if "m_current_value" is valid, false otherwise.
- //----------------------------------------------------------------------
- bool is_valid() const {
- if (m_invalid_value_is_valid)
- return m_current_value != m_invalid_value;
- return true;
- }
-
- //----------------------------------------------------------------------
- // This function will call the cleanup callback provided in the
- // constructor one time if the value is considered valid (See is_valid()).
- // This function sets m_callback_called to true so we don't call the
- // cleanup callback multiple times on the same value.
- //----------------------------------------------------------------------
- void clean() {
- if (m_callback && !m_callback_called) {
- m_callback_called = true;
- if (is_valid())
- m_callback(m_current_value);
- }
- }
+/// Run a cleanup function on scope exit unless it's explicitly disabled.
+class CleanUp {
+ std::function<void()> Clean;
- //----------------------------------------------------------------------
- // Cancels the cleanup that would have been called on "m_current_value"
- // if it was valid. This function can be used to release the value
- // contained in this object so ownership can be transferred to the caller.
- //----------------------------------------------------------------------
- value_type release() {
- m_callback_called = true;
- return m_current_value;
- }
-
-private:
- value_type m_current_value;
- const value_type m_invalid_value;
- CallbackType m_callback;
- bool m_callback_called;
- bool m_invalid_value_is_valid;
-
- // Outlaw default constructor, copy constructor and the assignment operator
- DISALLOW_COPY_AND_ASSIGN(CleanUp);
-};
-
-template <typename T, typename R, typename A0> class CleanUp2 {
public:
- typedef T value_type;
- typedef std::function<R(value_type, A0)> CallbackType;
-
- //----------------------------------------------------------------------
- // Constructor that sets the current value only. No values are
- // considered to be invalid and the cleanup function will be called
- // regardless of the value of m_current_value.
- //----------------------------------------------------------------------
- CleanUp2(value_type value, CallbackType callback, A0 arg)
- : m_current_value(value), m_invalid_value(), m_callback(callback),
- m_callback_called(false), m_invalid_value_is_valid(false),
- m_argument(arg) {}
-
- //----------------------------------------------------------------------
- // Constructor that sets the current value and also the invalid value.
- // The cleanup function will be called on "m_value" as long as it isn't
- // equal to "m_invalid_value".
- //----------------------------------------------------------------------
- CleanUp2(value_type value, value_type invalid, CallbackType callback, A0 arg)
- : m_current_value(value), m_invalid_value(invalid), m_callback(callback),
- m_callback_called(false), m_invalid_value_is_valid(true),
- m_argument(arg) {}
-
- //----------------------------------------------------------------------
- // Automatically cleanup when this object goes out of scope.
- //----------------------------------------------------------------------
- ~CleanUp2() { clean(); }
+ /// Register a cleanup function which applies \p Func to a list of arguments.
+ /// Use caution with arguments which are references: they will be copied.
+ template <typename F, typename... Args>
+ CleanUp(F &&Func, Args &&... args)
+ : Clean(std::bind(std::forward<F>(Func), std::forward<Args>(args)...)) {}
- //----------------------------------------------------------------------
- // Access the value stored in this class
- //----------------------------------------------------------------------
- value_type get() { return m_current_value; }
-
- //----------------------------------------------------------------------
- // Access the value stored in this class
- //----------------------------------------------------------------------
- const value_type get() const { return m_current_value; }
-
- //----------------------------------------------------------------------
- // Reset the owned value to "value". If a current value is valid and
- // the cleanup callback hasn't been called, the previous value will
- // be cleaned up (see void CleanUp::clean()).
- //----------------------------------------------------------------------
- void set(const value_type value) {
- // Cleanup the current value if needed
- clean();
- // Now set the new value and mark our callback as not called
- m_callback_called = false;
- m_current_value = value;
+ ~CleanUp() {
+ if (Clean)
+ Clean();
}
- //----------------------------------------------------------------------
- // Checks is "m_current_value" is valid. The value is considered valid
- // no invalid value was supplied during construction of this object or
- // if an invalid value was supplied and "m_current_value" is not equal
- // to "m_invalid_value".
- //
- // Returns true if "m_current_value" is valid, false otherwise.
- //----------------------------------------------------------------------
- bool is_valid() const {
- if (m_invalid_value_is_valid)
- return m_current_value != m_invalid_value;
- return true;
- }
-
- //----------------------------------------------------------------------
- // This function will call the cleanup callback provided in the
- // constructor one time if the value is considered valid (See is_valid()).
- // This function sets m_callback_called to true so we don't call the
- // cleanup callback multiple times on the same value.
- //----------------------------------------------------------------------
- void clean() {
- if (m_callback && !m_callback_called) {
- m_callback_called = true;
- if (is_valid())
- m_callback(m_current_value, m_argument);
- }
- }
+ /// Disable the cleanup.
+ void disable() { Clean = nullptr; }
- //----------------------------------------------------------------------
- // Cancels the cleanup that would have been called on "m_current_value"
- // if it was valid. This function can be used to release the value
- // contained in this object so ownership can be transferred to the caller.
- //----------------------------------------------------------------------
- value_type release() {
- m_callback_called = true;
- return m_current_value;
- }
-
-private:
- value_type m_current_value;
- const value_type m_invalid_value;
- CallbackType m_callback;
- bool m_callback_called;
- bool m_invalid_value_is_valid;
- A0 m_argument;
-
- // Outlaw default constructor, copy constructor and the assignment operator
- DISALLOW_COPY_AND_ASSIGN(CleanUp2);
+ // Prevent cleanups from being run more than once.
+ DISALLOW_COPY_AND_ASSIGN(CleanUp);
};
-} // namespace lldb_utility
+} // namespace lldb_private
#endif // #ifndef liblldb_CleanUp_h_
const lldb_private::UUID *uuid,
const ArchSpec *arch) {
char path[PATH_MAX];
+ if (dsym_bundle_fspec.GetPath(path, sizeof(path)) == 0)
+ return {};
- FileSpec dsym_fspec;
+ ::strncat(path, "/Contents/Resources/DWARF", sizeof(path) - strlen(path) - 1);
- if (dsym_bundle_fspec.GetPath(path, sizeof(path))) {
- ::strncat(path, "/Contents/Resources/DWARF",
- sizeof(path) - strlen(path) - 1);
-
- lldb_utility::CleanUp<DIR *, int> dirp(opendir(path), NULL, closedir);
- if (dirp.is_valid()) {
- dsym_fspec.GetDirectory().SetCString(path);
- struct dirent *dp;
- while ((dp = readdir(dirp.get())) != NULL) {
- // Only search directories
- if (dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN) {
- if (dp->d_namlen == 1 && dp->d_name[0] == '.')
- continue;
-
- if (dp->d_namlen == 2 && dp->d_name[0] == '.' && dp->d_name[1] == '.')
- continue;
- }
+ DIR *dirp = opendir(path);
+ if (!dirp)
+ return {};
- if (dp->d_type == DT_REG || dp->d_type == DT_UNKNOWN) {
- dsym_fspec.GetFilename().SetCString(dp->d_name);
- ModuleSpecList module_specs;
- if (ObjectFile::GetModuleSpecifications(dsym_fspec, 0, 0,
- module_specs)) {
- ModuleSpec spec;
- for (size_t i = 0; i < module_specs.GetSize(); ++i) {
- bool got_spec = module_specs.GetModuleSpecAtIndex(i, spec);
- UNUSED_IF_ASSERT_DISABLED(got_spec);
- assert(got_spec);
- if ((uuid == NULL ||
- (spec.GetUUIDPtr() && spec.GetUUID() == *uuid)) &&
- (arch == NULL ||
- (spec.GetArchitecturePtr() &&
- spec.GetArchitecture().IsCompatibleMatch(*arch)))) {
- return dsym_fspec;
- }
- }
+ // Make sure we close the directory before exiting this scope.
+ CleanUp cleanup_dir(closedir, dirp);
+
+ FileSpec dsym_fspec;
+ dsym_fspec.GetDirectory().SetCString(path);
+ struct dirent *dp;
+ while ((dp = readdir(dirp)) != NULL) {
+ // Only search directories
+ if (dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN) {
+ if (dp->d_namlen == 1 && dp->d_name[0] == '.')
+ continue;
+
+ if (dp->d_namlen == 2 && dp->d_name[0] == '.' && dp->d_name[1] == '.')
+ continue;
+ }
+
+ if (dp->d_type == DT_REG || dp->d_type == DT_UNKNOWN) {
+ dsym_fspec.GetFilename().SetCString(dp->d_name);
+ ModuleSpecList module_specs;
+ if (ObjectFile::GetModuleSpecifications(dsym_fspec, 0, 0, module_specs)) {
+ ModuleSpec spec;
+ for (size_t i = 0; i < module_specs.GetSize(); ++i) {
+ bool got_spec = module_specs.GetModuleSpecAtIndex(i, spec);
+ UNUSED_IF_ASSERT_DISABLED(got_spec);
+ assert(got_spec);
+ if ((uuid == NULL ||
+ (spec.GetUUIDPtr() && spec.GetUUID() == *uuid)) &&
+ (arch == NULL ||
+ (spec.GetArchitecturePtr() &&
+ spec.GetArchitecture().IsCompatibleMatch(*arch)))) {
+ return dsym_fspec;
}
}
}
}
}
- dsym_fspec.Clear();
- return dsym_fspec;
+
+ return {};
}
static bool GetModuleSpecInfoFromUUIDDictionary(CFDictionaryRef uuid_dict,