Patch by Hugo Santos:
* Print structures passed to ioctl() for several commands (networking and terminal). * Optional hex/decimal formatting of numbers (option -i). * New level of detail option -d. * Other improvements, like the introduction of a Context class to simplify passing around stuff. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20423 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
ea2de1a115
commit
567638c602
@ -3,11 +3,12 @@ SubDir HAIKU_TOP src bin strace ;
|
||||
UseArchHeaders $(TARGET_ARCH) ;
|
||||
UsePrivateHeaders kernel ;
|
||||
UsePrivateHeaders shared ;
|
||||
UsePrivateHeaders net ;
|
||||
|
||||
# find headers generated by gensyscalls
|
||||
SubDirHdrs $(TARGET_COMMON_DEBUG_LOCATE_TARGET) ;
|
||||
|
||||
local straceSources = strace.cpp MemoryReader.cpp TypeHandler.cpp ;
|
||||
local straceSources = strace.cpp MemoryReader.cpp TypeHandler.cpp ioctl.cpp ;
|
||||
|
||||
# Our compiler badly chokes when compiling the generated file. So will
|
||||
# split up the job into 20 pieces.
|
||||
|
@ -106,10 +106,50 @@ public:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static Syscall *GetSyscall(const char *);
|
||||
|
||||
private:
|
||||
string fName;
|
||||
Type *fReturnType;
|
||||
vector<Parameter*> fParameters;
|
||||
};
|
||||
|
||||
class Context {
|
||||
public:
|
||||
enum {
|
||||
STRINGS = 1 << 0,
|
||||
ENUMERATIONS = 1 << 1,
|
||||
SIMPLE_STRUCTS = 1 << 2,
|
||||
COMPLEX_STRUCTS = 1 << 3,
|
||||
ALL = 0xffffffff
|
||||
};
|
||||
|
||||
Context(Syscall *sc, char *data, MemoryReader &reader,
|
||||
uint32 flags, bool decimal)
|
||||
: fSyscall(sc), fData(data), fReader(reader),
|
||||
fFlags(flags), fDecimal(decimal) {}
|
||||
|
||||
Parameter *GetSibling(int32 index) const {
|
||||
return fSyscall->ParameterAt(index);
|
||||
}
|
||||
|
||||
const void *GetValue(Parameter *param) const {
|
||||
return fData + param->Offset();
|
||||
}
|
||||
|
||||
MemoryReader &Reader() { return fReader; }
|
||||
bool GetContents(uint32 what) const { return fFlags & what; }
|
||||
|
||||
string FormatSigned(int64 value, const char *modifier = "ll") const;
|
||||
string FormatUnsigned(uint64 value) const;
|
||||
string FormatFlags(uint64 value) const;
|
||||
|
||||
private:
|
||||
Syscall *fSyscall;
|
||||
char *fData;
|
||||
MemoryReader &fReader;
|
||||
uint32 fFlags;
|
||||
bool fDecimal;
|
||||
};
|
||||
|
||||
#endif // STRACE_SYSCALL_H
|
||||
|
@ -7,47 +7,38 @@
|
||||
* Hugo Santos <hugosantos@gmail.com>
|
||||
*/
|
||||
|
||||
#include "MemoryReader.h"
|
||||
#include "TypeHandler.h"
|
||||
|
||||
// headers required for network structures
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <net_stack_driver.h>
|
||||
|
||||
#include "MemoryReader.h"
|
||||
#include "Syscall.h"
|
||||
|
||||
// TypeHandlerImpl
|
||||
template<typename Type>
|
||||
class TypeHandlerImpl : public TypeHandler {
|
||||
public:
|
||||
virtual string GetParameterValue(const void *address, bool getContents,
|
||||
MemoryReader &reader);
|
||||
|
||||
virtual string GetReturnValue(uint64 value, bool getContents,
|
||||
MemoryReader &reader);
|
||||
virtual string GetParameterValue(Context &, Parameter *, const void *);
|
||||
virtual string GetReturnValue(Context &, uint64 value);
|
||||
};
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// get_number_value
|
||||
template<typename value_t>
|
||||
static inline
|
||||
string
|
||||
get_number_value(value_t value, const char *format)
|
||||
{
|
||||
char buffer[32];
|
||||
sprintf(buffer, format, value);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// get_number_value
|
||||
template<typename value_t>
|
||||
static inline
|
||||
string
|
||||
get_number_value(const void *address, const char *format)
|
||||
static inline value_t
|
||||
get_value(const void *address)
|
||||
{
|
||||
if (sizeof(align_t) > sizeof(value_t))
|
||||
return get_number_value<value_t>(value_t(*(align_t*)address), format);
|
||||
return value_t(*(align_t*)address);
|
||||
else
|
||||
return get_number_value<value_t>(*(value_t*)address, format);
|
||||
return *(value_t*)address;
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// get_pointer_value
|
||||
static inline
|
||||
string
|
||||
@ -82,13 +73,6 @@ create_string_type_handler()
|
||||
return new TypeHandlerImpl<const char*>();
|
||||
}
|
||||
|
||||
TypeHandler *
|
||||
create_fdset_type_handler()
|
||||
{
|
||||
return new TypeHandlerImpl<struct fd_set *>();
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// complete specializations
|
||||
@ -96,16 +80,14 @@ create_fdset_type_handler()
|
||||
// void
|
||||
template<>
|
||||
string
|
||||
TypeHandlerImpl<void>::GetParameterValue(const void *address, bool getContents,
|
||||
MemoryReader &reader)
|
||||
TypeHandlerImpl<void>::GetParameterValue(Context &, Parameter *, const void *)
|
||||
{
|
||||
return "void";
|
||||
}
|
||||
|
||||
template<>
|
||||
string
|
||||
TypeHandlerImpl<void>::GetReturnValue(uint64 value, bool getContents,
|
||||
MemoryReader &reader)
|
||||
TypeHandlerImpl<void>::GetReturnValue(Context &, uint64 value)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
@ -120,16 +102,15 @@ TypeHandlerFactory<void>::Create()
|
||||
// bool
|
||||
template<>
|
||||
string
|
||||
TypeHandlerImpl<bool>::GetParameterValue(const void *address, bool getContents,
|
||||
MemoryReader &reader)
|
||||
TypeHandlerImpl<bool>::GetParameterValue(Context &, Parameter *,
|
||||
const void *address)
|
||||
{
|
||||
return (*(align_t*)address ? "true" : "false");
|
||||
return (*(const align_t*)address ? "true" : "false");
|
||||
}
|
||||
|
||||
template<>
|
||||
string
|
||||
TypeHandlerImpl<bool>::GetReturnValue(uint64 value, bool getContents,
|
||||
MemoryReader &reader)
|
||||
TypeHandlerImpl<bool>::GetReturnValue(Context &, uint64 value)
|
||||
{
|
||||
return (value ? "true" : "false");
|
||||
}
|
||||
@ -141,223 +122,6 @@ TypeHandlerFactory<bool>::Create()
|
||||
return new TypeHandlerImpl<bool>();
|
||||
}
|
||||
|
||||
// char
|
||||
template<>
|
||||
string
|
||||
TypeHandlerImpl<char>::GetParameterValue(const void *address, bool getContents,
|
||||
MemoryReader &reader)
|
||||
{
|
||||
return get_number_value<char>(address, "0x%x");
|
||||
}
|
||||
|
||||
template<>
|
||||
string
|
||||
TypeHandlerImpl<char>::GetReturnValue(uint64 value, bool getContents,
|
||||
MemoryReader &reader)
|
||||
{
|
||||
return get_number_value<char>(value, "0x%x");
|
||||
}
|
||||
|
||||
template<>
|
||||
TypeHandler *
|
||||
TypeHandlerFactory<char>::Create()
|
||||
{
|
||||
return new TypeHandlerImpl<char>();
|
||||
}
|
||||
|
||||
// short
|
||||
template<>
|
||||
string
|
||||
TypeHandlerImpl<short>::GetParameterValue(const void *address, bool getContents,
|
||||
MemoryReader &reader)
|
||||
{
|
||||
return get_number_value<short>(address, "0x%x");
|
||||
}
|
||||
|
||||
template<>
|
||||
string
|
||||
TypeHandlerImpl<short>::GetReturnValue(uint64 value, bool getContents,
|
||||
MemoryReader &reader)
|
||||
{
|
||||
return get_number_value<short>(value, "0x%x");
|
||||
}
|
||||
|
||||
template<>
|
||||
TypeHandler *
|
||||
TypeHandlerFactory<short>::Create()
|
||||
{
|
||||
return new TypeHandlerImpl<short>();
|
||||
}
|
||||
|
||||
|
||||
// unsigned short
|
||||
template<>
|
||||
string
|
||||
TypeHandlerImpl<unsigned short>::GetParameterValue(const void *address,
|
||||
bool getContents, MemoryReader &reader)
|
||||
{
|
||||
return get_number_value<unsigned short>(address, "0x%x");
|
||||
}
|
||||
|
||||
template<>
|
||||
string
|
||||
TypeHandlerImpl<unsigned short>::GetReturnValue(uint64 value, bool getContents,
|
||||
MemoryReader &reader)
|
||||
{
|
||||
return get_number_value<unsigned short>(value, "0x%x");
|
||||
}
|
||||
|
||||
template<>
|
||||
TypeHandler *
|
||||
TypeHandlerFactory<unsigned short>::Create()
|
||||
{
|
||||
return new TypeHandlerImpl<unsigned short>();
|
||||
}
|
||||
|
||||
// int
|
||||
template<>
|
||||
string
|
||||
TypeHandlerImpl<int>::GetParameterValue(const void *address, bool getContents,
|
||||
MemoryReader &reader)
|
||||
{
|
||||
return get_number_value<int>(address, "0x%x");
|
||||
}
|
||||
|
||||
template<>
|
||||
string
|
||||
TypeHandlerImpl<int>::GetReturnValue(uint64 value, bool getContents,
|
||||
MemoryReader &reader)
|
||||
{
|
||||
return get_number_value<int>(value, "0x%x");
|
||||
}
|
||||
|
||||
template<>
|
||||
TypeHandler *
|
||||
TypeHandlerFactory<int>::Create()
|
||||
{
|
||||
return new TypeHandlerImpl<int>();
|
||||
}
|
||||
|
||||
// unsigned int
|
||||
template<>
|
||||
string
|
||||
TypeHandlerImpl<unsigned int>::GetParameterValue(const void *address,
|
||||
bool getContents, MemoryReader &reader)
|
||||
{
|
||||
return get_number_value<unsigned int>(address, "0x%x");
|
||||
}
|
||||
|
||||
template<>
|
||||
string
|
||||
TypeHandlerImpl<unsigned int>::GetReturnValue(uint64 value, bool getContents,
|
||||
MemoryReader &reader)
|
||||
{
|
||||
return get_number_value<unsigned int>(value, "0x%x");
|
||||
}
|
||||
|
||||
template<>
|
||||
TypeHandler *
|
||||
TypeHandlerFactory<unsigned int>::Create()
|
||||
{
|
||||
return new TypeHandlerImpl<unsigned int>();
|
||||
}
|
||||
|
||||
// long
|
||||
template<>
|
||||
string
|
||||
TypeHandlerImpl<long>::GetParameterValue(const void *address, bool getContents,
|
||||
MemoryReader &reader)
|
||||
{
|
||||
return get_number_value<long>(address, "0x%lx");
|
||||
}
|
||||
|
||||
template<>
|
||||
string
|
||||
TypeHandlerImpl<long>::GetReturnValue(uint64 value, bool getContents,
|
||||
MemoryReader &reader)
|
||||
{
|
||||
return get_number_value<long>(value, "0x%lx");
|
||||
}
|
||||
|
||||
template<>
|
||||
TypeHandler *
|
||||
TypeHandlerFactory<long>::Create()
|
||||
{
|
||||
return new TypeHandlerImpl<long>();
|
||||
}
|
||||
|
||||
// unsigned long
|
||||
template<>
|
||||
string
|
||||
TypeHandlerImpl<unsigned long>::GetParameterValue(const void *address,
|
||||
bool getContents, MemoryReader &reader)
|
||||
{
|
||||
return get_number_value<unsigned long>(address, "0x%lx");
|
||||
}
|
||||
|
||||
template<>
|
||||
string
|
||||
TypeHandlerImpl<unsigned long>::GetReturnValue(uint64 value, bool getContents,
|
||||
MemoryReader &reader)
|
||||
{
|
||||
return get_number_value<unsigned long>(value, "0x%lx");
|
||||
}
|
||||
|
||||
template<>
|
||||
TypeHandler *
|
||||
TypeHandlerFactory<unsigned long>::Create()
|
||||
{
|
||||
return new TypeHandlerImpl<unsigned long>();
|
||||
}
|
||||
|
||||
// long long
|
||||
template<>
|
||||
string
|
||||
TypeHandlerImpl<long long>::GetParameterValue(const void *address,
|
||||
bool getContents, MemoryReader &reader)
|
||||
{
|
||||
return get_number_value<long long>(address, "0x%llx");
|
||||
}
|
||||
|
||||
template<>
|
||||
string
|
||||
TypeHandlerImpl<long long>::GetReturnValue(uint64 value, bool getContents,
|
||||
MemoryReader &reader)
|
||||
{
|
||||
return get_number_value<long long>(value, "0x%llx");
|
||||
}
|
||||
|
||||
template<>
|
||||
TypeHandler *
|
||||
TypeHandlerFactory<long long>::Create()
|
||||
{
|
||||
return new TypeHandlerImpl<long long>();
|
||||
}
|
||||
|
||||
// unsigned long
|
||||
template<>
|
||||
string
|
||||
TypeHandlerImpl<unsigned long long>::GetParameterValue(const void *address,
|
||||
bool getContents, MemoryReader &reader)
|
||||
{
|
||||
return get_number_value<unsigned long>(address, "0x%llx");
|
||||
}
|
||||
|
||||
template<>
|
||||
string
|
||||
TypeHandlerImpl<unsigned long long>::GetReturnValue(uint64 value,
|
||||
bool getContents, MemoryReader &reader)
|
||||
{
|
||||
return get_number_value<unsigned long long>(value, "0x%llx");
|
||||
}
|
||||
|
||||
template<>
|
||||
TypeHandler *
|
||||
TypeHandlerFactory<unsigned long long>::Create()
|
||||
{
|
||||
return new TypeHandlerImpl<unsigned long long>();
|
||||
}
|
||||
|
||||
// read_string
|
||||
static
|
||||
string
|
||||
@ -388,13 +152,21 @@ read_string(MemoryReader &reader, void *data)
|
||||
}
|
||||
|
||||
static string
|
||||
read_fdset(MemoryReader &reader, void *data)
|
||||
format_number(uint32 value)
|
||||
{
|
||||
/* default FD_SETSIZE is 1024 */
|
||||
char tmp[32];
|
||||
snprintf(tmp, sizeof(tmp), "%u", (unsigned int)value);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static string
|
||||
read_fdset(Context &context, void *data)
|
||||
{
|
||||
// default FD_SETSIZE is 1024
|
||||
unsigned long tmp[1024 / (sizeof(unsigned long) * 8)];
|
||||
int32 bytesRead;
|
||||
|
||||
status_t err = reader.Read(data, &tmp, sizeof(tmp), bytesRead);
|
||||
status_t err = context.Reader().Read(data, &tmp, sizeof(tmp), bytesRead);
|
||||
if (err != B_OK)
|
||||
return get_pointer_value(&data);
|
||||
|
||||
@ -402,17 +174,19 @@ read_fdset(MemoryReader &reader, void *data)
|
||||
int count = bytesRead / sizeof(unsigned long);
|
||||
int added = 0;
|
||||
|
||||
string r = "[";
|
||||
string r;
|
||||
r.reserve(16);
|
||||
|
||||
r = "[";
|
||||
|
||||
for (int i = 0; i < count && added < 8; i++) {
|
||||
for (int j = 0;
|
||||
j < (int)(sizeof(unsigned long) * 8) && added < 8; j++) {
|
||||
if (tmp[i] & (1 << j)) {
|
||||
if (added > 0)
|
||||
r += ", ";
|
||||
r += get_number_value<unsigned long>(
|
||||
i * (sizeof(unsigned long) * 8) + j,
|
||||
"%u");
|
||||
r += " ";
|
||||
unsigned int fd = i * sizeof(unsigned long) * 8 + j;
|
||||
r += format_number(fd);
|
||||
added++;
|
||||
}
|
||||
}
|
||||
@ -421,22 +195,23 @@ read_fdset(MemoryReader &reader, void *data)
|
||||
if (added >= 8)
|
||||
r += " ...";
|
||||
|
||||
return r + "]";
|
||||
r += "]";
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
// const void*
|
||||
template<>
|
||||
string
|
||||
TypeHandlerImpl<const void*>::GetParameterValue(const void *address,
|
||||
bool getContents, MemoryReader &reader)
|
||||
TypeHandlerImpl<const void*>::GetParameterValue(Context &, Parameter *,
|
||||
const void *address)
|
||||
{
|
||||
return get_pointer_value(address);
|
||||
}
|
||||
|
||||
template<>
|
||||
string
|
||||
TypeHandlerImpl<const void*>::GetReturnValue(uint64 value, bool getContents,
|
||||
MemoryReader &reader)
|
||||
TypeHandlerImpl<const void*>::GetReturnValue(Context &, uint64 value)
|
||||
{
|
||||
return get_pointer_value(value);
|
||||
}
|
||||
@ -444,48 +219,317 @@ TypeHandlerImpl<const void*>::GetReturnValue(uint64 value, bool getContents,
|
||||
// const char*
|
||||
template<>
|
||||
string
|
||||
TypeHandlerImpl<const char*>::GetParameterValue(const void *address,
|
||||
bool getContents, MemoryReader &reader)
|
||||
TypeHandlerImpl<const char*>::GetParameterValue(Context &context, Parameter *,
|
||||
const void *address)
|
||||
{
|
||||
void *data = *(void**)address;
|
||||
if (getContents && data)
|
||||
return read_string(reader, data);
|
||||
void *data = *(void **)address;
|
||||
if (data != NULL && context.GetContents(Context::STRINGS))
|
||||
return read_string(context.Reader(), data);
|
||||
|
||||
return get_pointer_value(&data);
|
||||
}
|
||||
|
||||
template<>
|
||||
string
|
||||
TypeHandlerImpl<const char*>::GetReturnValue(uint64 value,
|
||||
bool getContents, MemoryReader &reader)
|
||||
TypeHandlerImpl<const char*>::GetReturnValue(Context &context, uint64 value)
|
||||
{
|
||||
void *data = (void*)value;
|
||||
if (getContents && data)
|
||||
return read_string(reader, data);
|
||||
|
||||
return get_pointer_value(&data);
|
||||
void *ptr = (void *)value;
|
||||
return GetParameterValue(context, NULL, (const void *)&ptr);
|
||||
}
|
||||
|
||||
// struct fd_set *
|
||||
template<>
|
||||
string
|
||||
TypeHandlerImpl<struct fd_set *>::GetParameterValue(const void *address,
|
||||
bool getContents, MemoryReader &reader)
|
||||
TypeHandlerImpl<struct fd_set *>::GetParameterValue(Context &context, Parameter *,
|
||||
const void *address)
|
||||
{
|
||||
void *data = *(void **)address;
|
||||
if (getContents && data)
|
||||
return read_fdset(reader, data);
|
||||
if (data != NULL && context.GetContents(Context::SIMPLE_STRUCTS))
|
||||
return read_fdset(context, data);
|
||||
return get_pointer_value(&data);
|
||||
}
|
||||
|
||||
template<>
|
||||
string
|
||||
TypeHandlerImpl<struct fd_set *>::GetReturnValue(uint64 value,
|
||||
bool getContents, MemoryReader &reader)
|
||||
TypeHandlerImpl<struct fd_set *>::GetReturnValue(Context &, uint64 value)
|
||||
{
|
||||
void *data = (void *)value;
|
||||
if (getContents && data)
|
||||
return read_fdset(reader, data);
|
||||
|
||||
return get_pointer_value(&data);
|
||||
return get_pointer_value(value);
|
||||
}
|
||||
|
||||
EnumTypeHandler::EnumTypeHandler(const EnumMap &m) : fMap(m) {}
|
||||
|
||||
string
|
||||
EnumTypeHandler::GetParameterValue(Context &context, Parameter *,
|
||||
const void *address)
|
||||
{
|
||||
return RenderValue(context, get_value<unsigned int>(address));
|
||||
}
|
||||
|
||||
string
|
||||
EnumTypeHandler::GetReturnValue(Context &context, uint64 value)
|
||||
{
|
||||
return RenderValue(context, value);
|
||||
}
|
||||
|
||||
string
|
||||
EnumTypeHandler::RenderValue(Context &context, unsigned int value) const
|
||||
{
|
||||
if (context.GetContents(Context::ENUMERATIONS)) {
|
||||
EnumMap::const_iterator i = fMap.find(value);
|
||||
if (i != fMap.end() && i->second != NULL)
|
||||
return i->second;
|
||||
}
|
||||
|
||||
return context.FormatUnsigned(value);
|
||||
}
|
||||
|
||||
TypeHandlerSelector::TypeHandlerSelector(const SelectMap &m, int sibling,
|
||||
TypeHandler *def)
|
||||
: fMap(m), fSibling(sibling), fDefault(def) {}
|
||||
|
||||
string
|
||||
TypeHandlerSelector::GetParameterValue(Context &context, Parameter *param,
|
||||
const void *address)
|
||||
{
|
||||
TypeHandler *target = fDefault;
|
||||
|
||||
int index = get_value<int>(context.GetValue(context.GetSibling(fSibling)));
|
||||
|
||||
SelectMap::const_iterator i = fMap.find(index);
|
||||
if (i != fMap.end())
|
||||
target = i->second;
|
||||
|
||||
return target->GetParameterValue(context, param, address);
|
||||
}
|
||||
|
||||
string
|
||||
TypeHandlerSelector::GetReturnValue(Context &context, uint64 value)
|
||||
{
|
||||
return fDefault->GetReturnValue(context, value);
|
||||
}
|
||||
|
||||
template<typename Base>
|
||||
static string
|
||||
format_pointer_deep(Context &context, void *address)
|
||||
{
|
||||
if (address == NULL || !context.GetContents(Context::COMPLEX_STRUCTS))
|
||||
return get_pointer_value(&address);
|
||||
|
||||
Base data;
|
||||
int32 bytesRead;
|
||||
|
||||
status_t err = context.Reader().Read(address, &data, sizeof(Base), bytesRead);
|
||||
if (err != B_OK || bytesRead < (int32)sizeof(Base))
|
||||
return get_pointer_value(&address);
|
||||
|
||||
return format_pointer(context, &data);
|
||||
}
|
||||
|
||||
template<typename Base>
|
||||
static string
|
||||
format_pointer_value(Context &context, const void *pointer)
|
||||
{
|
||||
return format_pointer_deep<Base>(context, *(void **)pointer);
|
||||
}
|
||||
|
||||
template<typename Base>
|
||||
static string
|
||||
format_pointer_value(Context &context, uint64 value)
|
||||
{
|
||||
return format_pointer_deep<Base>(context, (void *)value);
|
||||
}
|
||||
|
||||
static string
|
||||
get_ipv4_address(struct in_addr *addr)
|
||||
{
|
||||
char tmp[32];
|
||||
snprintf(tmp, sizeof(tmp), "%u.%u.%u.%u",
|
||||
(unsigned int)(htonl(addr->s_addr) >> 24) & 0xff,
|
||||
(unsigned int)(htonl(addr->s_addr) >> 16) & 0xff,
|
||||
(unsigned int)(htonl(addr->s_addr) >> 8) & 0xff,
|
||||
(unsigned int)(htonl(addr->s_addr) >> 0) & 0xff);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static string
|
||||
format_pointer(Context &context, sockaddr *saddr)
|
||||
{
|
||||
string r = "{";
|
||||
|
||||
struct sockaddr_in *sin = (struct sockaddr_in *)saddr;
|
||||
|
||||
switch (saddr->sa_family) {
|
||||
case AF_INET:
|
||||
r += "AF_INET, ";
|
||||
r += get_ipv4_address(&sin->sin_addr);
|
||||
r += "/";
|
||||
r += format_number(ntohs(sin->sin_port));
|
||||
break;
|
||||
|
||||
default:
|
||||
r += "family = ";
|
||||
r += context.FormatUnsigned(saddr->sa_family);
|
||||
r += ", ...";
|
||||
break;
|
||||
}
|
||||
|
||||
return r + "}";
|
||||
}
|
||||
|
||||
static string
|
||||
format_pointer(Context &context, sockaddr_args *args)
|
||||
{
|
||||
string r = "{";
|
||||
|
||||
r += "addr = " + format_pointer_deep<struct sockaddr>(context, args->address);
|
||||
r += ", len = " + context.FormatUnsigned(args->address_length);
|
||||
|
||||
return r + "}";
|
||||
}
|
||||
|
||||
static string
|
||||
format_pointer(Context &context, transfer_args *args)
|
||||
{
|
||||
string r = "{";
|
||||
|
||||
r += "data = " + get_pointer_value(&args->data);
|
||||
r += ", len = " + context.FormatUnsigned(args->data_length);
|
||||
r += ", flags = " + context.FormatFlags(args->flags);
|
||||
r += ", addr = " + format_pointer_deep<struct sockaddr>(context, args->address);
|
||||
|
||||
return r + "}";
|
||||
}
|
||||
|
||||
static string
|
||||
format_pointer(Context &context, sockopt_args *args)
|
||||
{
|
||||
string r = "{";
|
||||
|
||||
r += "level = " + context.FormatSigned(args->level);
|
||||
r += ", option = " + context.FormatSigned(args->option);
|
||||
r += ", value = " + get_pointer_value(args->value);
|
||||
r += ", len = " + context.FormatSigned(args->length);
|
||||
|
||||
return r + "}";
|
||||
}
|
||||
|
||||
static string
|
||||
get_iovec(Context &context, struct iovec *iov, int iovlen)
|
||||
{
|
||||
string r = "{";
|
||||
r += get_pointer_value(&iov);
|
||||
r += ", " + context.FormatSigned(iovlen);
|
||||
return r + "}";
|
||||
}
|
||||
|
||||
static string
|
||||
format_pointer(Context &context, msghdr *h)
|
||||
{
|
||||
string r = "{";
|
||||
|
||||
r += "name = " + format_pointer_deep<struct sockaddr>(context, h->msg_name);
|
||||
r += ", name_len = " + context.FormatUnsigned(h->msg_namelen);
|
||||
r += ", iov = " + get_iovec(context, h->msg_iov, h->msg_iovlen);
|
||||
r += ", control = " + get_pointer_value(&h->msg_control);
|
||||
r += ", control_len = " + context.FormatUnsigned(h->msg_controllen);
|
||||
r += ", flags = " + context.FormatFlags(h->msg_flags);
|
||||
|
||||
return r + "}";
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
class SignedIntegerTypeHandler : public TypeHandler {
|
||||
public:
|
||||
SignedIntegerTypeHandler(const char *modifier)
|
||||
: fModifier(modifier) {}
|
||||
|
||||
string GetParameterValue(Context &context, Parameter *,
|
||||
const void *address)
|
||||
{
|
||||
return context.FormatSigned(get_value<Type>(address), fModifier);
|
||||
}
|
||||
|
||||
string GetReturnValue(Context &context, uint64 value)
|
||||
{
|
||||
return context.FormatSigned(value, fModifier);
|
||||
}
|
||||
|
||||
private:
|
||||
const char *fModifier;
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
class UnsignedIntegerTypeHandler : public TypeHandler {
|
||||
public:
|
||||
string GetParameterValue(Context &context, Parameter *,
|
||||
const void *address)
|
||||
{
|
||||
return context.FormatUnsigned(get_value<Type>(address));
|
||||
}
|
||||
|
||||
string GetReturnValue(Context &context, uint64 value)
|
||||
{
|
||||
return context.FormatUnsigned(value);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
class SpecializedPointerTypeHandler : public TypeHandler {
|
||||
string GetParameterValue(Context &context, Parameter *,
|
||||
const void *address)
|
||||
{
|
||||
return format_pointer_value<Type>(context, address);
|
||||
}
|
||||
|
||||
string GetReturnValue(Context &context, uint64 value)
|
||||
{
|
||||
return format_pointer_value<Type>(context, value);
|
||||
}
|
||||
};
|
||||
|
||||
#define DEFINE_TYPE(name, type) \
|
||||
TypeHandler *create_##name##_type_handler() \
|
||||
{ \
|
||||
return new TypeHandlerImpl<type>(); \
|
||||
}
|
||||
|
||||
#define SIGNED_INTEGER_TYPE(type, modifier) \
|
||||
template<> \
|
||||
TypeHandler * \
|
||||
TypeHandlerFactory<type>::Create() \
|
||||
{ \
|
||||
return new SignedIntegerTypeHandler<type>(modifier); \
|
||||
}
|
||||
|
||||
#define UNSIGNED_INTEGER_TYPE(type) \
|
||||
template<> \
|
||||
TypeHandler * \
|
||||
TypeHandlerFactory<type>::Create() \
|
||||
{ \
|
||||
return new UnsignedIntegerTypeHandler<type>(); \
|
||||
}
|
||||
|
||||
#define POINTER_TYPE(name, type) \
|
||||
TypeHandler *create_##name##_type_handler() \
|
||||
{ \
|
||||
return new SpecializedPointerTypeHandler<type>(); \
|
||||
}
|
||||
|
||||
SIGNED_INTEGER_TYPE(char, "hh");
|
||||
SIGNED_INTEGER_TYPE(short, "h");
|
||||
SIGNED_INTEGER_TYPE(int, "");
|
||||
SIGNED_INTEGER_TYPE(long, "l");
|
||||
SIGNED_INTEGER_TYPE(long long, "ll");
|
||||
|
||||
UNSIGNED_INTEGER_TYPE(unsigned char);
|
||||
UNSIGNED_INTEGER_TYPE(unsigned short);
|
||||
UNSIGNED_INTEGER_TYPE(unsigned int);
|
||||
UNSIGNED_INTEGER_TYPE(unsigned long);
|
||||
UNSIGNED_INTEGER_TYPE(unsigned long long);
|
||||
|
||||
DEFINE_TYPE(fdset_ptr, struct fd_set *);
|
||||
POINTER_TYPE(sockaddr_args_ptr, struct sockaddr_args);
|
||||
POINTER_TYPE(transfer_args_ptr, struct transfer_args);
|
||||
POINTER_TYPE(sockopt_args_ptr, struct sockopt_args);
|
||||
POINTER_TYPE(msghdr_ptr, struct msghdr);
|
||||
|
||||
|
@ -10,12 +10,15 @@
|
||||
#define STRACE_TYPE_HANDLER_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include <arch_config.h>
|
||||
#include <SupportDefs.h>
|
||||
|
||||
using std::string;
|
||||
|
||||
class Context;
|
||||
class Parameter;
|
||||
class MemoryReader;
|
||||
|
||||
typedef FUNCTION_CALL_PARAMETER_ALIGNMENT_TYPE align_t;
|
||||
@ -26,11 +29,41 @@ public:
|
||||
TypeHandler() {}
|
||||
virtual ~TypeHandler() {}
|
||||
|
||||
virtual string GetParameterValue(const void *address, bool getContents,
|
||||
MemoryReader &reader) = 0;
|
||||
virtual string GetParameterValue(Context &, Parameter *,
|
||||
const void *value) = 0;
|
||||
virtual string GetReturnValue(Context &, uint64 value) = 0;
|
||||
};
|
||||
|
||||
virtual string GetReturnValue(uint64 value, bool getContents,
|
||||
MemoryReader &reader) = 0;
|
||||
class EnumTypeHandler : public TypeHandler {
|
||||
public:
|
||||
typedef std::map<int, const char *> EnumMap;
|
||||
|
||||
EnumTypeHandler(const EnumMap &);
|
||||
|
||||
string GetParameterValue(Context &c, Parameter *, const void *);
|
||||
string GetReturnValue(Context &, uint64 value);
|
||||
|
||||
private:
|
||||
string RenderValue(Context &, unsigned int value) const;
|
||||
|
||||
const EnumMap &fMap;
|
||||
};
|
||||
|
||||
// currently limited to select ints
|
||||
class TypeHandlerSelector : public TypeHandler {
|
||||
public:
|
||||
typedef std::map<int, TypeHandler *> SelectMap;
|
||||
|
||||
TypeHandlerSelector(const SelectMap &, int sibling,
|
||||
TypeHandler *def);
|
||||
|
||||
string GetParameterValue(Context &, Parameter *, const void *);
|
||||
string GetReturnValue(Context &, uint64 value);
|
||||
|
||||
private:
|
||||
const SelectMap &fMap;
|
||||
int fSibling;
|
||||
TypeHandler *fDefault;
|
||||
};
|
||||
|
||||
// templatized TypeHandler factory class
|
||||
@ -44,7 +77,6 @@ struct TypeHandlerFactory {
|
||||
|
||||
extern TypeHandler *create_pointer_type_handler();
|
||||
extern TypeHandler *create_string_type_handler();
|
||||
extern TypeHandler *create_fdset_type_handler();
|
||||
|
||||
// specialization for "const char*"
|
||||
template<>
|
||||
@ -55,14 +87,20 @@ struct TypeHandlerFactory<const char*> {
|
||||
}
|
||||
};
|
||||
|
||||
// specialization for 'struct fdset *'
|
||||
template<>
|
||||
struct TypeHandlerFactory<struct fd_set *> {
|
||||
static inline TypeHandler *Create()
|
||||
{
|
||||
return create_fdset_type_handler();
|
||||
}
|
||||
};
|
||||
#define DEFINE_FACTORY(name, type) \
|
||||
template<> \
|
||||
struct TypeHandlerFactory<type> { \
|
||||
static inline TypeHandler *Create() \
|
||||
{ \
|
||||
extern TypeHandler *create_##name##_type_handler(); \
|
||||
return create_##name##_type_handler(); \
|
||||
} \
|
||||
} \
|
||||
|
||||
DEFINE_FACTORY(fdset_ptr, struct fd_set *);
|
||||
DEFINE_FACTORY(sockaddr_args_ptr, struct sockaddr_args *);
|
||||
DEFINE_FACTORY(transfer_args_ptr, struct transfer_args *);
|
||||
DEFINE_FACTORY(sockopt_args_ptr, struct sockopt_args *);
|
||||
|
||||
// partial specialization for generic pointers
|
||||
template<typename Type>
|
||||
|
91
src/bin/strace/ioctl.cpp
Normal file
91
src/bin/strace/ioctl.cpp
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 2007, Haiku Inc. All rights reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Hugo Santos <hugosantos@gmail.com>
|
||||
*/
|
||||
|
||||
#include <net_stack_driver.h>
|
||||
#include <termios.h>
|
||||
|
||||
#include "Syscall.h"
|
||||
#include "TypeHandler.h"
|
||||
|
||||
struct ioctl_info {
|
||||
int index;
|
||||
const char *name;
|
||||
TypeHandler *handler;
|
||||
};
|
||||
|
||||
#define IOCTL_INFO_ENTRY(name) \
|
||||
{ name, #name, NULL }
|
||||
|
||||
#define IOCTL_INFO_ENTRY_TYPE(name, type) \
|
||||
{ name, #name, TypeHandlerFactory<type>::Create() }
|
||||
|
||||
static const ioctl_info kIOCtls[] = {
|
||||
// network stack ioctls
|
||||
IOCTL_INFO_ENTRY(NET_STACK_SOCKET),
|
||||
IOCTL_INFO_ENTRY(NET_STACK_GET_COOKIE),
|
||||
IOCTL_INFO_ENTRY(NET_STACK_CONTROL_NET_MODULE),
|
||||
IOCTL_INFO_ENTRY(NET_STACK_GET_NEXT_STAT),
|
||||
IOCTL_INFO_ENTRY_TYPE(NET_STACK_BIND, struct sockaddr_args *),
|
||||
IOCTL_INFO_ENTRY_TYPE(NET_STACK_RECVFROM, struct transfer_args *),
|
||||
IOCTL_INFO_ENTRY_TYPE(NET_STACK_RECV, struct transfer_args *),
|
||||
IOCTL_INFO_ENTRY_TYPE(NET_STACK_SENDTO, struct transfer_args *),
|
||||
IOCTL_INFO_ENTRY_TYPE(NET_STACK_SEND, struct transfer_args *),
|
||||
IOCTL_INFO_ENTRY(NET_STACK_LISTEN),
|
||||
IOCTL_INFO_ENTRY(NET_STACK_ACCEPT),
|
||||
IOCTL_INFO_ENTRY_TYPE(NET_STACK_CONNECT, struct sockaddr_args *),
|
||||
IOCTL_INFO_ENTRY(NET_STACK_SHUTDOWN),
|
||||
IOCTL_INFO_ENTRY_TYPE(NET_STACK_GETSOCKOPT, struct sockopt_args *),
|
||||
IOCTL_INFO_ENTRY_TYPE(NET_STACK_SETSOCKOPT, struct sockopt_args *),
|
||||
IOCTL_INFO_ENTRY_TYPE(NET_STACK_GETSOCKNAME, struct sockaddr_args *),
|
||||
IOCTL_INFO_ENTRY_TYPE(NET_STACK_GETPEERNAME, struct sockaddr_args *),
|
||||
IOCTL_INFO_ENTRY(NET_STACK_SOCKETPAIR),
|
||||
IOCTL_INFO_ENTRY(NET_STACK_NOTIFY_SOCKET_EVENT),
|
||||
|
||||
// termios ioctls
|
||||
IOCTL_INFO_ENTRY(TCGETA),
|
||||
IOCTL_INFO_ENTRY(TCSETA),
|
||||
IOCTL_INFO_ENTRY(TCSETAF),
|
||||
IOCTL_INFO_ENTRY(TCSETAW),
|
||||
IOCTL_INFO_ENTRY(TCWAITEVENT),
|
||||
IOCTL_INFO_ENTRY(TCSBRK),
|
||||
IOCTL_INFO_ENTRY(TCFLSH),
|
||||
IOCTL_INFO_ENTRY(TCXONC),
|
||||
IOCTL_INFO_ENTRY(TCQUERYCONNECTED),
|
||||
IOCTL_INFO_ENTRY(TCGETBITS),
|
||||
IOCTL_INFO_ENTRY(TCSETDTR),
|
||||
IOCTL_INFO_ENTRY(TCSETRTS),
|
||||
IOCTL_INFO_ENTRY(TIOCGWINSZ),
|
||||
IOCTL_INFO_ENTRY(TIOCSWINSZ),
|
||||
IOCTL_INFO_ENTRY(TCVTIME),
|
||||
IOCTL_INFO_ENTRY(TIOCGPGRP),
|
||||
IOCTL_INFO_ENTRY(TIOCSPGRP),
|
||||
|
||||
{ -1, NULL, NULL }
|
||||
};
|
||||
|
||||
static EnumTypeHandler::EnumMap kIoctlNames;
|
||||
static TypeHandlerSelector::SelectMap kIoctlTypeHandlers;
|
||||
|
||||
void
|
||||
patch_ioctl()
|
||||
{
|
||||
for (int i = 0; kIOCtls[i].name != NULL; i++) {
|
||||
kIoctlNames[kIOCtls[i].index] = kIOCtls[i].name;
|
||||
if (kIOCtls[i].handler != NULL)
|
||||
kIoctlTypeHandlers[kIOCtls[i].index] = kIOCtls[i].handler;
|
||||
}
|
||||
|
||||
Syscall *ioctl = Syscall::GetSyscall("_kern_ioctl");
|
||||
|
||||
ioctl->GetParameter("cmd")->SetHandler(
|
||||
new EnumTypeHandler(kIoctlNames));
|
||||
ioctl->GetParameter("data")->SetHandler(
|
||||
new TypeHandlerSelector(kIoctlTypeHandlers,
|
||||
1, TypeHandlerFactory<void *>::Create()));
|
||||
}
|
||||
|
@ -59,8 +59,11 @@ static const char *kUsage =
|
||||
"Options:\n"
|
||||
" -a - Don't print syscall arguments.\n"
|
||||
" -c - Don't colorize output.\n"
|
||||
" -d <name> - Filter the types that have their contents retrieved.\n"
|
||||
" <name> is one of: strings, enums, simple or complex\n"
|
||||
" -f - Fast mode. Syscall arguments contents aren't retrieved.\n"
|
||||
" -h, --help - Print this text.\n"
|
||||
" -i - Print integers in decimal format instead of hexadecimal.\n"
|
||||
" -l - Also trace loading the excecutable. Only considered when\n"
|
||||
" an executable is provided.\n"
|
||||
" -r - Don't print syscall return values.\n"
|
||||
@ -88,7 +91,6 @@ static const char *const *sArgv;
|
||||
static vector<Syscall*> sSyscallVector;
|
||||
static map<string, Syscall*> sSyscallMap;
|
||||
|
||||
|
||||
// print_usage
|
||||
void
|
||||
print_usage(bool error)
|
||||
@ -266,6 +268,17 @@ continue_thread(port_id nubPort, thread_id thread)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
patch_syscalls()
|
||||
{
|
||||
// instead of having this done here manually we should either add the
|
||||
// patching step to gensyscalls also manually or add metadata to
|
||||
// kernel/syscalls.h and have it parsed automatically
|
||||
extern void patch_ioctl();
|
||||
|
||||
patch_ioctl();
|
||||
}
|
||||
|
||||
// init_syscalls
|
||||
static
|
||||
void
|
||||
@ -299,6 +312,8 @@ init_syscalls()
|
||||
Syscall *syscall = sSyscallVector[i];
|
||||
sSyscallMap[syscall->Name()] = syscall;
|
||||
}
|
||||
|
||||
patch_syscalls();
|
||||
}
|
||||
|
||||
// print_to_string
|
||||
@ -319,14 +334,17 @@ print_to_string(char **_buffer, int32 *_length, const char *format, ...)
|
||||
static
|
||||
void
|
||||
print_syscall(FILE *outputFile, debug_post_syscall &message,
|
||||
MemoryReader &memoryReader, bool printArguments, bool getContents,
|
||||
bool printReturnValue, bool colorize)
|
||||
MemoryReader &memoryReader, bool printArguments, uint32 contentsFlags,
|
||||
bool printReturnValue, bool colorize, bool decimal)
|
||||
{
|
||||
char buffer[4096], *string = buffer;
|
||||
int32 length = (int32)sizeof(buffer);
|
||||
int32 syscallNumber = message.syscall;
|
||||
Syscall *syscall = sSyscallVector[syscallNumber];
|
||||
|
||||
Context ctx(syscall, (char *)message.args, memoryReader,
|
||||
contentsFlags, decimal);
|
||||
|
||||
// print syscall name
|
||||
if (colorize) {
|
||||
print_to_string(&string, &length, "[%6ld] %s%s%s(",
|
||||
@ -344,9 +362,9 @@ print_syscall(FILE *outputFile, debug_post_syscall &message,
|
||||
// get the value
|
||||
Parameter *parameter = syscall->ParameterAt(i);
|
||||
TypeHandler *handler = parameter->Handler();
|
||||
::string value = handler->GetParameterValue(
|
||||
(char*)message.args + parameter->Offset(), getContents,
|
||||
memoryReader);
|
||||
::string value =
|
||||
handler->GetParameterValue(ctx, parameter,
|
||||
ctx.GetValue(parameter));
|
||||
|
||||
print_to_string(&string, &length, (i > 0 ? ", %s" : "%s"),
|
||||
value.c_str());
|
||||
@ -359,8 +377,7 @@ print_syscall(FILE *outputFile, debug_post_syscall &message,
|
||||
if (printReturnValue) {
|
||||
Type *returnType = syscall->ReturnType();
|
||||
TypeHandler *handler = returnType->Handler();
|
||||
::string value = handler->GetReturnValue(message.return_value,
|
||||
getContents, memoryReader);
|
||||
::string value = handler->GetReturnValue(ctx, message.return_value);
|
||||
if (value.length() > 0) {
|
||||
print_to_string(&string, &length, " = %s", value.c_str());
|
||||
|
||||
@ -414,6 +431,8 @@ main(int argc, const char *const *argv)
|
||||
int32 programArgCount = 0;
|
||||
bool printArguments = true;
|
||||
bool colorize = true;
|
||||
uint32 contentsFlags = 0;
|
||||
bool decimalFormat = false;
|
||||
bool fastMode = false;
|
||||
bool traceLoading = false;
|
||||
bool printReturnValues = true;
|
||||
@ -433,8 +452,33 @@ main(int argc, const char *const *argv)
|
||||
printArguments = false;
|
||||
} else if (strcmp(arg, "-c") == 0) {
|
||||
colorize = false;
|
||||
} else if (strcmp(arg, "-d") == 0) {
|
||||
const char *what = NULL;
|
||||
|
||||
if (arg[2] == '\0'
|
||||
&& argi + 1 < argc && argv[argi + 1][0] != '-') {
|
||||
// next arg is what
|
||||
what = argv[++argi];
|
||||
} else
|
||||
print_usage_and_exit(true);
|
||||
|
||||
if (strcasecmp(what, "strings") == 0)
|
||||
contentsFlags |= Context::STRINGS;
|
||||
else if (strcasecmp(what, "enums") == 0)
|
||||
contentsFlags |= Context::ENUMERATIONS;
|
||||
else if (strcasecmp(what, "simple") == 0)
|
||||
contentsFlags |= Context::SIMPLE_STRUCTS;
|
||||
else if (strcasecmp(what, "complex") == 0)
|
||||
contentsFlags |= Context::COMPLEX_STRUCTS;
|
||||
else {
|
||||
fprintf(stderr, "%s: Unknown content filter `%s'\n",
|
||||
kCommandName, what);
|
||||
exit(1);
|
||||
}
|
||||
} else if (strcmp(arg, "-f") == 0) {
|
||||
fastMode = true;
|
||||
} else if (strcmp(arg, "-i") == 0) {
|
||||
decimalFormat = true;
|
||||
} else if (strcmp(arg, "-l") == 0) {
|
||||
traceLoading = true;
|
||||
} else if (strcmp(arg, "-r") == 0) {
|
||||
@ -479,6 +523,11 @@ main(int argc, const char *const *argv)
|
||||
if (!programArgs)
|
||||
print_usage_and_exit(true);
|
||||
|
||||
if (fastMode)
|
||||
contentsFlags = 0;
|
||||
else if (contentsFlags == 0)
|
||||
contentsFlags = Context::ALL;
|
||||
|
||||
// initialize our syscalls vector and map
|
||||
init_syscalls();
|
||||
|
||||
@ -500,7 +549,7 @@ main(int argc, const char *const *argv)
|
||||
programArgs[0], strerror(thread));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get the team ID, if we have none yet
|
||||
if (team < 0) {
|
||||
@ -571,7 +620,8 @@ main(int argc, const char *const *argv)
|
||||
case B_DEBUGGER_MESSAGE_POST_SYSCALL:
|
||||
{
|
||||
print_syscall(outputFile, message.post_syscall, memoryReader,
|
||||
printArguments, !fastMode, printReturnValues, colorize);
|
||||
printArguments, contentsFlags, printReturnValues,
|
||||
colorize, decimalFormat);
|
||||
|
||||
break;
|
||||
}
|
||||
@ -611,3 +661,43 @@ main(int argc, const char *const *argv)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Syscall *
|
||||
Syscall::GetSyscall(const char *name)
|
||||
{
|
||||
map<string, Syscall *>::const_iterator i = sSyscallMap.find(name);
|
||||
if (i == sSyscallMap.end())
|
||||
return NULL;
|
||||
|
||||
return i->second;
|
||||
}
|
||||
|
||||
string
|
||||
Context::FormatSigned(int64 value, const char *type) const
|
||||
{
|
||||
char modifier[16], tmp[32];
|
||||
|
||||
if (fDecimal)
|
||||
snprintf(modifier, sizeof(modifier), "%%%si", type);
|
||||
else
|
||||
snprintf(modifier, sizeof(modifier), "0x%%%sx", type);
|
||||
|
||||
snprintf(tmp, sizeof(tmp), modifier, value);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
string
|
||||
Context::FormatUnsigned(uint64 value) const
|
||||
{
|
||||
char tmp[32];
|
||||
snprintf(tmp, sizeof(tmp), fDecimal ? "%llu" : "0x%llx", value);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
string
|
||||
Context::FormatFlags(uint64 value) const
|
||||
{
|
||||
char tmp[32];
|
||||
snprintf(tmp, sizeof(tmp), "0x%llx", value);
|
||||
return tmp;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user