mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-01-08 00:52:54 +00:00
Add methods to enable using formatv syntax in LLDB.
This adds formatv-backed formatting functions in various places in LLDB such as StreamString, logging, constructing error messages, etc. A couple of callsites are changed from Printf style syntax to formatv style syntax to illustrate its usage. Additionally, a FileSpec formatter is introduced so that FileSpecs can be formatted natively. Differential Revision: https://reviews.llvm.org/D27632 llvm-svn: 289922
This commit is contained in:
parent
db4c86f953
commit
827d5d74a5
@ -19,6 +19,8 @@
|
||||
|
||||
#include "lldb/lldb-private.h"
|
||||
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
|
||||
namespace lldb_private {
|
||||
|
||||
class Log;
|
||||
@ -258,6 +260,11 @@ public:
|
||||
|
||||
int SetErrorStringWithVarArg(const char *format, va_list args);
|
||||
|
||||
template <typename... Args>
|
||||
void SetErrorStringWithFormatv(const char *format, Args &&... args) {
|
||||
SetErrorString(llvm::formatv(format, std::forward<Args>(args)...).str());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Test for success condition.
|
||||
///
|
||||
|
@ -25,6 +25,8 @@
|
||||
#include "lldb/Core/PluginInterface.h"
|
||||
#include "lldb/lldb-private.h"
|
||||
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Logging Options
|
||||
//----------------------------------------------------------------------
|
||||
@ -43,7 +45,7 @@
|
||||
//----------------------------------------------------------------------
|
||||
namespace lldb_private {
|
||||
|
||||
class Log {
|
||||
class Log final {
|
||||
public:
|
||||
//------------------------------------------------------------------
|
||||
// Callback definitions for abstracted plug-in log access.
|
||||
@ -102,42 +104,32 @@ public:
|
||||
|
||||
Log(const lldb::StreamSP &stream_sp);
|
||||
|
||||
virtual ~Log();
|
||||
~Log();
|
||||
|
||||
virtual void PutCString(const char *cstr);
|
||||
virtual void PutString(llvm::StringRef str);
|
||||
void PutCString(const char *cstr);
|
||||
void PutString(llvm::StringRef str);
|
||||
|
||||
template <typename... Args> void Format(const char *fmt, Args &&... args) {
|
||||
PutString(llvm::formatv(fmt, std::forward<Args>(args)...).str());
|
||||
}
|
||||
|
||||
// CLEANUP: Add llvm::raw_ostream &Stream() function.
|
||||
virtual void Printf(const char *format, ...)
|
||||
__attribute__((format(printf, 2, 3)));
|
||||
void Printf(const char *format, ...) __attribute__((format(printf, 2, 3)));
|
||||
|
||||
virtual void VAPrintf(const char *format, va_list args);
|
||||
void VAPrintf(const char *format, va_list args);
|
||||
|
||||
virtual void LogIf(uint32_t mask, const char *fmt, ...)
|
||||
void LogIf(uint32_t mask, const char *fmt, ...)
|
||||
__attribute__((format(printf, 3, 4)));
|
||||
|
||||
virtual void Debug(const char *fmt, ...)
|
||||
__attribute__((format(printf, 2, 3)));
|
||||
void Debug(const char *fmt, ...) __attribute__((format(printf, 2, 3)));
|
||||
|
||||
virtual void DebugVerbose(const char *fmt, ...)
|
||||
__attribute__((format(printf, 2, 3)));
|
||||
void Error(const char *fmt, ...) __attribute__((format(printf, 2, 3)));
|
||||
|
||||
virtual void Error(const char *fmt, ...)
|
||||
__attribute__((format(printf, 2, 3)));
|
||||
void VAError(const char *format, va_list args);
|
||||
|
||||
virtual void VAError(const char *format, va_list args);
|
||||
void Verbose(const char *fmt, ...) __attribute__((format(printf, 2, 3)));
|
||||
|
||||
virtual void FatalError(int err, const char *fmt, ...)
|
||||
__attribute__((format(printf, 3, 4)));
|
||||
|
||||
virtual void Verbose(const char *fmt, ...)
|
||||
__attribute__((format(printf, 2, 3)));
|
||||
|
||||
virtual void Warning(const char *fmt, ...)
|
||||
__attribute__((format(printf, 2, 3)));
|
||||
|
||||
virtual void WarningVerbose(const char *fmt, ...)
|
||||
__attribute__((format(printf, 2, 3)));
|
||||
void Warning(const char *fmt, ...) __attribute__((format(printf, 2, 3)));
|
||||
|
||||
Flags &GetOptions();
|
||||
|
||||
|
@ -240,7 +240,7 @@ public:
|
||||
if (m_object_mod_time != llvm::sys::TimePoint<>()) {
|
||||
if (dumped_something)
|
||||
strm.PutCString(", ");
|
||||
strm.Printf("object_mod_time = 0x%" PRIx64,
|
||||
strm.Format("object_mod_time = {0:x+}",
|
||||
uint64_t(llvm::sys::toTimeT(m_object_mod_time)));
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,8 @@
|
||||
#include "lldb/Core/Flags.h"
|
||||
#include "lldb/lldb-private.h"
|
||||
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
|
||||
namespace lldb_private {
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
@ -485,6 +487,10 @@ public:
|
||||
|
||||
size_t PrintfVarArg(const char *format, va_list args);
|
||||
|
||||
template <typename... Args> void Format(const char *format, Args &&... args) {
|
||||
PutCString(llvm::formatv(format, std::forward<Args>(args)...).str());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Output a quoted C string value to the stream.
|
||||
///
|
||||
|
@ -22,6 +22,8 @@
|
||||
#include "lldb/Host/PosixApi.h"
|
||||
#include "lldb/lldb-private.h"
|
||||
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
|
||||
namespace lldb_private {
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
@ -759,4 +761,30 @@ Stream &operator<<(Stream &s, const FileSpec &f);
|
||||
|
||||
} // namespace lldb_private
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// Implementation of format_provider<T> for FileSpec.
|
||||
///
|
||||
/// The options string of a FileSpec has the grammar:
|
||||
///
|
||||
/// file_spec_options :: (empty) | F | D
|
||||
///
|
||||
/// =======================================================
|
||||
/// | style | Meaning | Example |
|
||||
/// -------------------------------------------------------
|
||||
/// | | | Input | Output |
|
||||
/// =======================================================
|
||||
/// | F | Only print filename | /foo/bar | bar |
|
||||
/// | D | Only print directory | /foo/bar | /foo/ |
|
||||
/// | (empty) | Print file and dir | | |
|
||||
/// =======================================================
|
||||
///
|
||||
/// Any other value is considered an invalid format string.
|
||||
///
|
||||
template <> struct format_provider<lldb_private::FileSpec> {
|
||||
static void format(const lldb_private::FileSpec &F, llvm::raw_ostream &Stream,
|
||||
StringRef Style);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // liblldb_FileSpec_h_
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "lldb/lldb-private.h"
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
@ -113,6 +114,21 @@ public:
|
||||
void AppendErrorWithFormat(const char *format, ...)
|
||||
__attribute__((format(printf, 2, 3)));
|
||||
|
||||
template <typename... Args>
|
||||
void AppendMessageWithFormatv(const char *format, Args &&... args) {
|
||||
AppendMessage(llvm::formatv(format, std::forward<Args>(args)...).str());
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void AppendWarningWithFormatv(const char *format, Args &&... args) {
|
||||
AppendWarning(llvm::formatv(format, std::forward<Args>(args)...).str());
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void AppendErrorWithFormatv(const char *format, Args &&... args) {
|
||||
AppendError(llvm::formatv(format, std::forward<Args>(args)...).str());
|
||||
}
|
||||
|
||||
void SetError(const Error &error, const char *fallback_error_cstr = nullptr);
|
||||
|
||||
void SetError(llvm::StringRef error_cstr);
|
||||
|
@ -86,8 +86,8 @@ BreakpointOptions::CommandData::CreateFromStructuredData(
|
||||
found_something = true;
|
||||
interp_language = ScriptInterpreter::StringToLanguage(interpreter_str);
|
||||
if (interp_language == eScriptLanguageUnknown) {
|
||||
error.SetErrorStringWithFormat("Unknown breakpoint command language: %s.",
|
||||
interpreter_str.c_str());
|
||||
error.SetErrorStringWithFormatv("Unknown breakpoint command language: {0}.",
|
||||
interpreter_str);
|
||||
return data_up;
|
||||
}
|
||||
data_up->interpreter = interp_language;
|
||||
|
@ -90,9 +90,9 @@ bool CommandObjectApropos::DoExecute(Args &args, CommandReturnObject &result) {
|
||||
m_interpreter.GetDebugger().Apropos(search_word, properties);
|
||||
if (num_properties) {
|
||||
const bool dump_qualified_name = true;
|
||||
result.AppendMessageWithFormat(
|
||||
"\nThe following settings variables may relate to '%s': \n\n",
|
||||
args[0].c_str());
|
||||
result.AppendMessageWithFormatv(
|
||||
"\nThe following settings variables may relate to '{0}': \n\n",
|
||||
args[0].ref);
|
||||
for (size_t i = 0; i < num_properties; ++i)
|
||||
properties[i]->DumpDescription(
|
||||
m_interpreter, result.GetOutputStream(), 0, dump_qualified_name);
|
||||
|
@ -137,20 +137,6 @@ void Log::Debug(const char *format, ...) {
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Print debug strings if and only if the global debug option is set to
|
||||
// a non-zero value.
|
||||
//----------------------------------------------------------------------
|
||||
void Log::DebugVerbose(const char *format, ...) {
|
||||
if (!GetOptions().AllSet(LLDB_LOG_OPTION_DEBUG | LLDB_LOG_OPTION_VERBOSE))
|
||||
return;
|
||||
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
VAPrintf(format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Log only if all of the bits are set
|
||||
//----------------------------------------------------------------------
|
||||
@ -185,24 +171,6 @@ void Log::VAError(const char *format, va_list args) {
|
||||
free(arg_msg);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Printing of errors that ARE fatal. Exit with ERR exit code
|
||||
// immediately.
|
||||
//----------------------------------------------------------------------
|
||||
void Log::FatalError(int err, const char *format, ...) {
|
||||
char *arg_msg = nullptr;
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
::vasprintf(&arg_msg, format, args);
|
||||
va_end(args);
|
||||
|
||||
if (arg_msg != nullptr) {
|
||||
Printf("error: %s", arg_msg);
|
||||
::free(arg_msg);
|
||||
}
|
||||
::exit(err);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Printing of warnings that are not fatal only if verbose mode is
|
||||
// enabled.
|
||||
@ -217,27 +185,6 @@ void Log::Verbose(const char *format, ...) {
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Printing of warnings that are not fatal only if verbose mode is
|
||||
// enabled.
|
||||
//----------------------------------------------------------------------
|
||||
void Log::WarningVerbose(const char *format, ...) {
|
||||
if (!m_options.Test(LLDB_LOG_OPTION_VERBOSE))
|
||||
return;
|
||||
|
||||
char *arg_msg = nullptr;
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
::vasprintf(&arg_msg, format, args);
|
||||
va_end(args);
|
||||
|
||||
if (arg_msg == nullptr)
|
||||
return;
|
||||
|
||||
Printf("warning: %s", arg_msg);
|
||||
free(arg_msg);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Printing of warnings that are not fatal.
|
||||
//----------------------------------------------------------------------
|
||||
|
@ -354,10 +354,10 @@ void FileSpec::SetFile(llvm::StringRef pathname, bool resolve,
|
||||
m_is_resolved = true;
|
||||
}
|
||||
|
||||
Normalize(resolved, syntax);
|
||||
Normalize(resolved, m_syntax);
|
||||
|
||||
llvm::StringRef resolve_path_ref(resolved.c_str());
|
||||
size_t dir_end = ParentPathEnd(resolve_path_ref, syntax);
|
||||
size_t dir_end = ParentPathEnd(resolve_path_ref, m_syntax);
|
||||
if (dir_end == 0) {
|
||||
m_filename.SetString(resolve_path_ref);
|
||||
return;
|
||||
@ -366,11 +366,11 @@ void FileSpec::SetFile(llvm::StringRef pathname, bool resolve,
|
||||
m_directory.SetString(resolve_path_ref.substr(0, dir_end));
|
||||
|
||||
size_t filename_begin = dir_end;
|
||||
size_t root_dir_start = RootDirStart(resolve_path_ref, syntax);
|
||||
size_t root_dir_start = RootDirStart(resolve_path_ref, m_syntax);
|
||||
while (filename_begin != llvm::StringRef::npos &&
|
||||
filename_begin < resolve_path_ref.size() &&
|
||||
filename_begin != root_dir_start &&
|
||||
IsPathSeparator(resolve_path_ref[filename_begin], syntax))
|
||||
IsPathSeparator(resolve_path_ref[filename_begin], m_syntax))
|
||||
++filename_begin;
|
||||
m_filename.SetString((filename_begin == llvm::StringRef::npos ||
|
||||
filename_begin >= resolve_path_ref.size())
|
||||
@ -1386,3 +1386,46 @@ bool FileSpec::IsRelative() const {
|
||||
}
|
||||
|
||||
bool FileSpec::IsAbsolute() const { return !FileSpec::IsRelative(); }
|
||||
|
||||
void llvm::format_provider<FileSpec>::format(const FileSpec &F,
|
||||
raw_ostream &Stream,
|
||||
StringRef Style) {
|
||||
assert(
|
||||
(Style.empty() || Style.equals_lower("F") || Style.equals_lower("D")) &&
|
||||
"Invalid FileSpec style!");
|
||||
|
||||
StringRef dir = F.GetDirectory().GetStringRef();
|
||||
StringRef file = F.GetFilename().GetStringRef();
|
||||
|
||||
if (dir.empty() && file.empty()) {
|
||||
Stream << "(empty)";
|
||||
return;
|
||||
}
|
||||
|
||||
if (Style.equals_lower("F")) {
|
||||
Stream << (file.empty() ? "(empty)" : file);
|
||||
return;
|
||||
}
|
||||
|
||||
// Style is either D or empty, either way we need to print the directory.
|
||||
if (!dir.empty()) {
|
||||
// Directory is stored in normalized form, which might be different
|
||||
// than preferred form. In order to handle this, we need to cut off
|
||||
// the filename, then denormalize, then write the entire denorm'ed
|
||||
// directory.
|
||||
llvm::SmallString<64> denormalized_dir = dir;
|
||||
Denormalize(denormalized_dir, F.GetPathSyntax());
|
||||
Stream << denormalized_dir;
|
||||
Stream << GetPreferredPathSeparator(F.GetPathSyntax());
|
||||
}
|
||||
|
||||
if (Style.equals_lower("D")) {
|
||||
// We only want to print the directory, so now just exit.
|
||||
if (dir.empty())
|
||||
Stream << "(empty)";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!file.empty())
|
||||
Stream << file;
|
||||
}
|
||||
|
@ -9,6 +9,9 @@
|
||||
|
||||
#include "lldb/Symbol/ClangASTContext.h"
|
||||
|
||||
#include "llvm/Support/FormatAdapters.h"
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
|
||||
// C Includes
|
||||
// C++ Includes
|
||||
#include <mutex> // std::once
|
||||
@ -6739,10 +6742,7 @@ CompilerType ClangASTContext::GetChildCompilerTypeAtIndex(
|
||||
if (array) {
|
||||
CompilerType element_type(getASTContext(), array->getElementType());
|
||||
if (element_type.GetCompleteType()) {
|
||||
char element_name[64];
|
||||
::snprintf(element_name, sizeof(element_name), "[%" PRIu64 "]",
|
||||
static_cast<uint64_t>(idx));
|
||||
child_name.assign(element_name);
|
||||
child_name = llvm::formatv("[{0}]", idx);
|
||||
child_byte_size = element_type.GetByteSize(
|
||||
exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL);
|
||||
child_byte_offset = (int32_t)idx * (int32_t)child_byte_size;
|
||||
@ -8883,8 +8883,8 @@ void ClangASTContext::DumpValue(
|
||||
std::string base_class_type_name(base_class_qual_type.getAsString());
|
||||
|
||||
// Indent and print the base class type name
|
||||
s->Printf("\n%*s%s ", depth + DEPTH_INCREMENT, "",
|
||||
base_class_type_name.c_str());
|
||||
s->Format("\n{0}{1}", llvm::fmt_repeat(" ", depth + DEPTH_INCREMENT),
|
||||
base_class_type_name);
|
||||
|
||||
clang::TypeInfo base_class_type_info =
|
||||
getASTContext()->getTypeInfo(base_class_qual_type);
|
||||
|
@ -1554,11 +1554,9 @@ size_t Target::ReadMemory(const Address &addr, bool prefer_file_cache,
|
||||
if (load_addr == LLDB_INVALID_ADDRESS) {
|
||||
ModuleSP addr_module_sp(resolved_addr.GetModule());
|
||||
if (addr_module_sp && addr_module_sp->GetFileSpec())
|
||||
error.SetErrorStringWithFormat(
|
||||
"%s[0x%" PRIx64 "] can't be resolved, %s in not currently loaded",
|
||||
addr_module_sp->GetFileSpec().GetFilename().AsCString("<Unknown>"),
|
||||
resolved_addr.GetFileAddress(),
|
||||
addr_module_sp->GetFileSpec().GetFilename().AsCString("<Unknonw>"));
|
||||
error.SetErrorStringWithFormatv(
|
||||
"{0:F}[{1:x+}] can't be resolved, {0:F} is not currently loaded",
|
||||
addr_module_sp->GetFileSpec(), resolved_addr.GetFileAddress());
|
||||
else
|
||||
error.SetErrorStringWithFormat("0x%" PRIx64 " can't be resolved",
|
||||
resolved_addr.GetFileAddress());
|
||||
|
@ -260,3 +260,27 @@ TEST(FileSpecTest, GetNormalizedPath) {
|
||||
<< "Original path: " << test.first;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(FileSpecTest, FormatFileSpec) {
|
||||
auto win = FileSpec::ePathSyntaxWindows;
|
||||
|
||||
FileSpec F;
|
||||
EXPECT_EQ("(empty)", llvm::formatv("{0}", F).str());
|
||||
EXPECT_EQ("(empty)", llvm::formatv("{0:D}", F).str());
|
||||
EXPECT_EQ("(empty)", llvm::formatv("{0:F}", F).str());
|
||||
|
||||
F = FileSpec("C:\\foo\\bar.txt", false, win);
|
||||
EXPECT_EQ("C:\\foo\\bar.txt", llvm::formatv("{0}", F).str());
|
||||
EXPECT_EQ("C:\\foo\\", llvm::formatv("{0:D}", F).str());
|
||||
EXPECT_EQ("bar.txt", llvm::formatv("{0:F}", F).str());
|
||||
|
||||
F = FileSpec("foo\\bar.txt", false, win);
|
||||
EXPECT_EQ("foo\\bar.txt", llvm::formatv("{0}", F).str());
|
||||
EXPECT_EQ("foo\\", llvm::formatv("{0:D}", F).str());
|
||||
EXPECT_EQ("bar.txt", llvm::formatv("{0:F}", F).str());
|
||||
|
||||
F = FileSpec("foo", false, win);
|
||||
EXPECT_EQ("foo", llvm::formatv("{0}", F).str());
|
||||
EXPECT_EQ("foo", llvm::formatv("{0:F}", F).str());
|
||||
EXPECT_EQ("(empty)", llvm::formatv("{0:D}", F).str());
|
||||
}
|
Loading…
Reference in New Issue
Block a user