* Moved strace source into separate subdirectory.
* Now syscall names and parameters are printed. const char* parameters and return values are retrieved from the client and printed as string. * Missing are still color output (does consoled support that?) and searching for given commands in the PATH. Nothing besides the standard mode has been tested yet, so it's probably not working. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@11345 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
SubDir OBOS_TOP src apps bin strace ;
|
||||
|
||||
# We need our objects dir in the include paths.
|
||||
SetupObjectsDir ;
|
||||
|
||||
UseArchHeaders $(OBOS_ARCH) ;
|
||||
UsePrivateHeaders kernel ;
|
||||
UsePrivateHeaders shared ;
|
||||
|
||||
local straceSources = strace.cpp MemoryReader.cpp TypeHandler.cpp ;
|
||||
|
||||
local straceSyscallsIndices
|
||||
= 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ;
|
||||
|
||||
local straceSyscallsSource = [ FGristFiles strace_syscalls.cpp ] ;
|
||||
local straceSyscallsObjects ;
|
||||
|
||||
local i ;
|
||||
for i in $(straceSyscallsIndices) {
|
||||
local object = [ FGristFiles strace_syscalls$(i).o ] ;
|
||||
straceSyscallsObjects += $(object) ;
|
||||
|
||||
Object $(object) : $(straceSyscallsSource) ;
|
||||
|
||||
ObjectDefines $(object)
|
||||
: GET_SYSCALLS=get_syscalls$(i) SYSCALLS_CHUNK_$(i) ;
|
||||
}
|
||||
|
||||
BinCommand strace : $(straceSources)
|
||||
: $(straceSyscallsObjects) libroot.so libstdc++.r4.so ;
|
||||
|
||||
# We need to specify the dependency on the generated syscalls file explicitly.
|
||||
Includes $(straceSyscallsSource) : <syscalls>strace_syscalls.h ;
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright 2005, Ingo Weinhold, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <debugger.h>
|
||||
|
||||
#include "MemoryReader.h"
|
||||
|
||||
// constructor
|
||||
MemoryReader::MemoryReader(port_id nubPort)
|
||||
: fNubPort(nubPort),
|
||||
fReplyPort(-1)
|
||||
{
|
||||
fReplyPort = create_port(1, "memory reader reply");
|
||||
if (fReplyPort < 0) {
|
||||
fprintf(stderr, "Failed to create memory reader reply port: %s\n",
|
||||
strerror(fReplyPort));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// constructor
|
||||
MemoryReader::~MemoryReader()
|
||||
{
|
||||
if (fReplyPort >= 0)
|
||||
delete_port(fReplyPort);
|
||||
}
|
||||
|
||||
// Read
|
||||
status_t
|
||||
MemoryReader::Read(void *_address, void *_buffer, int32 size, int32 &bytesRead)
|
||||
{
|
||||
char *address = (char*)_address;
|
||||
char *buffer = (char*)_buffer;
|
||||
bytesRead = 0;
|
||||
|
||||
// If the region to be read crosses page boundaries, we split it up into
|
||||
// smaller chunks.
|
||||
while (size > 0) {
|
||||
int32 toRead = size;
|
||||
if (toRead > B_MAX_READ_WRITE_MEMORY_SIZE)
|
||||
toRead = B_MAX_READ_WRITE_MEMORY_SIZE;
|
||||
if ((uint32)address % B_PAGE_SIZE + toRead > B_PAGE_SIZE)
|
||||
toRead = B_PAGE_SIZE - (uint32)address % B_PAGE_SIZE;
|
||||
|
||||
status_t error = _Read(address, buffer, toRead);
|
||||
|
||||
// If reading fails, we only fail, if we haven't read something yet.
|
||||
if (error != B_OK) {
|
||||
if (bytesRead > 0)
|
||||
return B_OK;
|
||||
return error;
|
||||
}
|
||||
|
||||
bytesRead += toRead;
|
||||
address += toRead;
|
||||
buffer += toRead;
|
||||
size -= toRead;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// _Read
|
||||
status_t
|
||||
MemoryReader::_Read(void *address, void *buffer, int32 size)
|
||||
{
|
||||
// prepare message
|
||||
debug_nub_read_memory message;
|
||||
message.reply_port = fReplyPort;
|
||||
message.address = address;
|
||||
message.size = size;
|
||||
|
||||
// send message
|
||||
while (true) {
|
||||
status_t error = write_port(fNubPort, B_DEBUG_MESSAGE_READ_MEMORY,
|
||||
&message, sizeof(message));
|
||||
if (error == B_OK)
|
||||
break;
|
||||
if (error != B_INTERRUPTED)
|
||||
return error;
|
||||
}
|
||||
|
||||
// get reply
|
||||
int32 code;
|
||||
debug_nub_read_memory_reply reply;
|
||||
while (true) {
|
||||
ssize_t bytesRead = read_port(fReplyPort, &code, &reply, sizeof(reply));
|
||||
if (bytesRead > 0)
|
||||
break;
|
||||
if (bytesRead != B_INTERRUPTED)
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
if (reply.error != B_OK)
|
||||
return reply.error;
|
||||
|
||||
memcpy(buffer, reply.data, size);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2005, Ingo Weinhold, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef STRACE_MEMORY_READER_H
|
||||
#define STRACE_MEMORY_READER_H
|
||||
|
||||
#include <OS.h>
|
||||
|
||||
class MemoryReader {
|
||||
public:
|
||||
MemoryReader(port_id nubPort);
|
||||
~MemoryReader();
|
||||
|
||||
status_t Read(void *address, void *buffer, int32 size, int32 &bytesRead);
|
||||
|
||||
private:
|
||||
status_t _Read(void *address, void *buffer, int32 size);
|
||||
|
||||
port_id fNubPort;
|
||||
port_id fReplyPort;
|
||||
};
|
||||
|
||||
|
||||
#endif // STRACE_MEMORY_READER_H
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2005, Ingo Weinhold, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef STRACE_SYSCALL_H
|
||||
#define STRACE_SYSCALL_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
#include "TypeHandler.h"
|
||||
|
||||
// Type
|
||||
class Type {
|
||||
public:
|
||||
Type(TypeHandler *handler) : fHandler(handler) {}
|
||||
|
||||
void SetHandler(TypeHandler *handler)
|
||||
{
|
||||
delete fHandler;
|
||||
fHandler = handler;
|
||||
}
|
||||
|
||||
TypeHandler *Handler() const { return fHandler; }
|
||||
|
||||
private:
|
||||
TypeHandler *fHandler;
|
||||
};
|
||||
|
||||
// Parameter
|
||||
class Parameter : public Type {
|
||||
public:
|
||||
Parameter(string name, int32 offset, TypeHandler *handler)
|
||||
: Type(handler),
|
||||
fName(name),
|
||||
fOffset(offset)
|
||||
{
|
||||
}
|
||||
|
||||
const string &Name() const { return fName; }
|
||||
int32 Offset() const { return fOffset; }
|
||||
|
||||
private:
|
||||
string fName;
|
||||
int32 fOffset;
|
||||
};
|
||||
|
||||
// Syscall
|
||||
class Syscall {
|
||||
public:
|
||||
Syscall(string name, TypeHandler *returnTypeHandler)
|
||||
: fName(name), fReturnType(new Type(returnTypeHandler)) {}
|
||||
|
||||
const string &Name() const
|
||||
{
|
||||
return fName;
|
||||
}
|
||||
|
||||
Type *ReturnType() const
|
||||
{
|
||||
return fReturnType;
|
||||
}
|
||||
|
||||
void AddParameter(Parameter *parameter)
|
||||
{
|
||||
fParameters.push_back(parameter);
|
||||
}
|
||||
|
||||
void AddParameter(string name, int32 offset, TypeHandler *handler)
|
||||
{
|
||||
AddParameter(new Parameter(name, offset, handler));
|
||||
}
|
||||
|
||||
int32 CountParameters() const
|
||||
{
|
||||
return fParameters.size();
|
||||
}
|
||||
|
||||
Parameter *ParameterAt(int32 index) const
|
||||
{
|
||||
return fParameters[index];
|
||||
}
|
||||
|
||||
Parameter *GetParameter(string name) const
|
||||
{
|
||||
int32 count = CountParameters();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
Parameter *parameter = ParameterAt(i);
|
||||
if (parameter->Name() == name)
|
||||
return parameter;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
string fName;
|
||||
Type *fReturnType;
|
||||
vector<Parameter*> fParameters;
|
||||
};
|
||||
|
||||
#endif // STRACE_SYSCALL_H
|
||||
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
* Copyright 2005, Ingo Weinhold, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include "MemoryReader.h"
|
||||
#include "TypeHandler.h"
|
||||
|
||||
// complete specializations
|
||||
|
||||
// void
|
||||
template<>
|
||||
string
|
||||
TypeHandlerImpl<void>::GetParameterValue(const void *address, bool getContents,
|
||||
MemoryReader &reader)
|
||||
{
|
||||
return "void";
|
||||
}
|
||||
|
||||
template<>
|
||||
string
|
||||
TypeHandlerImpl<void>::GetReturnValue(uint64 value, bool getContents,
|
||||
MemoryReader &reader)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
// bool
|
||||
template<>
|
||||
string
|
||||
TypeHandlerImpl<bool>::GetParameterValue(const void *address, bool getContents,
|
||||
MemoryReader &reader)
|
||||
{
|
||||
return (*(align_t*)address ? "true" : "false");
|
||||
}
|
||||
|
||||
template<>
|
||||
string
|
||||
TypeHandlerImpl<bool>::GetReturnValue(uint64 value, bool getContents,
|
||||
MemoryReader &reader)
|
||||
{
|
||||
return (value ? "true" : "false");
|
||||
}
|
||||
|
||||
// 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");
|
||||
}
|
||||
|
||||
// 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");
|
||||
}
|
||||
|
||||
// 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");
|
||||
}
|
||||
|
||||
// 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");
|
||||
}
|
||||
|
||||
// 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");
|
||||
}
|
||||
|
||||
// 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");
|
||||
}
|
||||
|
||||
// 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");
|
||||
}
|
||||
|
||||
// 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");
|
||||
}
|
||||
|
||||
// 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");
|
||||
}
|
||||
|
||||
// read_string
|
||||
static
|
||||
string
|
||||
read_string(MemoryReader &reader, void *data)
|
||||
{
|
||||
char buffer[256];
|
||||
int32 bytesRead;
|
||||
status_t error = reader.Read(data, buffer, sizeof(buffer), bytesRead);
|
||||
if (error == B_OK) {
|
||||
// return string("\"") + string(buffer, bytesRead) + "\"";
|
||||
//string result("\"");
|
||||
//result += string(buffer, bytesRead);
|
||||
//result += "\"";
|
||||
//return result;
|
||||
|
||||
// TODO: Unless I'm missing something obvious, our STL string class is broken.
|
||||
// The appended "\"" doesn't appear in either of the above cases.
|
||||
|
||||
int32 len = strnlen(buffer, sizeof(buffer));
|
||||
char largeBuffer[259];
|
||||
largeBuffer[0] = '"';
|
||||
memcpy(largeBuffer + 1, buffer, len);
|
||||
largeBuffer[len + 1] = '"';
|
||||
largeBuffer[len + 2] = '\0';
|
||||
return largeBuffer;
|
||||
}
|
||||
return get_pointer_value(&data) + " (" + strerror(error) + ")";
|
||||
}
|
||||
|
||||
|
||||
// const char*
|
||||
template<>
|
||||
string
|
||||
TypeHandlerImpl<const char*>::GetParameterValue(const void *address,
|
||||
bool getContents, MemoryReader &reader)
|
||||
{
|
||||
void *data = *(void**)address;
|
||||
if (getContents && data)
|
||||
return read_string(reader, data);
|
||||
|
||||
return get_pointer_value(&data);
|
||||
}
|
||||
|
||||
template<>
|
||||
string
|
||||
TypeHandlerImpl<const char*>::GetReturnValue(uint64 value,
|
||||
bool getContents, MemoryReader &reader)
|
||||
{
|
||||
void *data = (void*)value;
|
||||
if (getContents && data)
|
||||
return read_string(reader, data);
|
||||
|
||||
return get_pointer_value(&data);
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright 2005, Ingo Weinhold, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef STRACE_TYPE_HANDLER_H
|
||||
#define STRACE_TYPE_HANDLER_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <arch_config.h>
|
||||
#include <SupportDefs.h>
|
||||
|
||||
class MemoryReader;
|
||||
|
||||
typedef FUNCTION_CALL_PARAMETER_ALIGNMENT_TYPE align_t;
|
||||
|
||||
// TypeHandler
|
||||
class TypeHandler {
|
||||
public:
|
||||
TypeHandler() {}
|
||||
virtual ~TypeHandler() {}
|
||||
|
||||
virtual string GetParameterValue(const void *address, bool getContents,
|
||||
MemoryReader &reader) = 0;
|
||||
|
||||
virtual string GetReturnValue(uint64 value, bool getContents,
|
||||
MemoryReader &reader) = 0;
|
||||
};
|
||||
|
||||
// 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);
|
||||
};
|
||||
|
||||
|
||||
// TypeHandlerImpl
|
||||
template<typename Type>
|
||||
class TypeHandlerImpl<Type*> : public TypeHandler {
|
||||
public:
|
||||
virtual string GetParameterValue(const void *address, bool getContents,
|
||||
MemoryReader &reader);
|
||||
|
||||
virtual string GetReturnValue(uint64 value, bool getContents,
|
||||
MemoryReader &reader);
|
||||
};
|
||||
|
||||
//// TypeHandlerImpl
|
||||
//template<>
|
||||
//class TypeHandlerImpl<const char*> : public TypeHandler {
|
||||
//public:
|
||||
// virtual string GetParameterValue(const void *address, bool getContents,
|
||||
// MemoryReader &reader);
|
||||
//
|
||||
// virtual string GetReturnValue(uint64 value, bool getContents,
|
||||
// MemoryReader &reader);
|
||||
//};
|
||||
|
||||
// get_number_value
|
||||
template<typename value_t>
|
||||
static inline
|
||||
string
|
||||
get_number_value(const void *address, const char *format)
|
||||
{
|
||||
if (sizeof(align_t) > sizeof(value_t))
|
||||
return get_number_value<value_t>(value_t(*(align_t*)address), format);
|
||||
else
|
||||
return get_number_value<value_t>(*(value_t*)address, format);
|
||||
}
|
||||
|
||||
// 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_pointer_value
|
||||
static inline
|
||||
string
|
||||
get_pointer_value(const void *address)
|
||||
{
|
||||
char buffer[32];
|
||||
sprintf(buffer, "%p", *(void **)address);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// get_pointer_value
|
||||
static inline
|
||||
string
|
||||
get_pointer_value(uint64 value)
|
||||
{
|
||||
char buffer[32];
|
||||
sprintf(buffer, "%p", (void*)value);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// generic pointer
|
||||
template<typename Type>
|
||||
string
|
||||
TypeHandlerImpl<Type*>::GetParameterValue(const void *address, bool getContents,
|
||||
MemoryReader &reader)
|
||||
{
|
||||
return get_pointer_value(address);
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
string
|
||||
TypeHandlerImpl<Type*>::GetReturnValue(uint64 value, bool getContents,
|
||||
MemoryReader &reader)
|
||||
{
|
||||
return get_pointer_value(value);
|
||||
}
|
||||
|
||||
#endif // STRACE_TYPE_HANDLER_H
|
||||
@@ -0,0 +1,480 @@
|
||||
/*
|
||||
* Copyright 2005, Ingo Weinhold, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <debugger.h>
|
||||
#include <image.h>
|
||||
|
||||
#include "MemoryReader.h"
|
||||
#include "Syscall.h"
|
||||
#include "TypeHandler.h"
|
||||
|
||||
extern void get_syscalls0(vector<Syscall*> &syscalls);
|
||||
extern void get_syscalls1(vector<Syscall*> &syscalls);
|
||||
extern void get_syscalls2(vector<Syscall*> &syscalls);
|
||||
extern void get_syscalls3(vector<Syscall*> &syscalls);
|
||||
extern void get_syscalls4(vector<Syscall*> &syscalls);
|
||||
extern void get_syscalls5(vector<Syscall*> &syscalls);
|
||||
extern void get_syscalls6(vector<Syscall*> &syscalls);
|
||||
extern void get_syscalls7(vector<Syscall*> &syscalls);
|
||||
extern void get_syscalls8(vector<Syscall*> &syscalls);
|
||||
extern void get_syscalls9(vector<Syscall*> &syscalls);
|
||||
extern void get_syscalls10(vector<Syscall*> &syscalls);
|
||||
extern void get_syscalls11(vector<Syscall*> &syscalls);
|
||||
extern void get_syscalls12(vector<Syscall*> &syscalls);
|
||||
extern void get_syscalls13(vector<Syscall*> &syscalls);
|
||||
extern void get_syscalls14(vector<Syscall*> &syscalls);
|
||||
extern void get_syscalls15(vector<Syscall*> &syscalls);
|
||||
extern void get_syscalls16(vector<Syscall*> &syscalls);
|
||||
extern void get_syscalls17(vector<Syscall*> &syscalls);
|
||||
extern void get_syscalls18(vector<Syscall*> &syscalls);
|
||||
extern void get_syscalls19(vector<Syscall*> &syscalls);
|
||||
|
||||
static const char *kDefaultCommandName = "strace";
|
||||
|
||||
// usage
|
||||
static const char *kUsage =
|
||||
"Usage: %s [ <options> ] [ <thread or team ID> | <executable with args> ]\n"
|
||||
"\n"
|
||||
"Traces the the syscalls of a thread or a team. If an executable with\n"
|
||||
"arguments is supplied, it is loaded and it's main thread traced.\n"
|
||||
"\n"
|
||||
"Options:\n"
|
||||
" -a - Don't print syscall arguments.\n"
|
||||
" -c - Don't colorize output.\n"
|
||||
" -f - Fast mode. Syscall arguments contents aren't retrieved.\n"
|
||||
" -h, --help - Print this text.\n"
|
||||
" -r - Don't print syscall return values.\n"
|
||||
" -s - Also trace all threads spawned by the supplied thread,\n"
|
||||
" respectively the loaded executable's main thread.\n"
|
||||
" -T - Trace all threads of the supplied or loaded executable's\n"
|
||||
" team. If an ID is supplied, it is interpreted as a team\n"
|
||||
" ID."
|
||||
;
|
||||
|
||||
// command line args
|
||||
static int sArgc;
|
||||
static const char *const *sArgv;
|
||||
|
||||
// syscalls
|
||||
static vector<Syscall*> sSyscallVector;
|
||||
static map<string, Syscall*> sSyscallMap;
|
||||
|
||||
|
||||
// print_usage
|
||||
void
|
||||
print_usage(bool error)
|
||||
{
|
||||
// get nice program name
|
||||
const char *programName = (sArgc > 0 ? sArgv[0] : kDefaultCommandName);
|
||||
if (const char *lastSlash = strrchr(programName, '/'))
|
||||
programName = lastSlash + 1;
|
||||
|
||||
// print usage
|
||||
fprintf((error ? stderr : stdout), kUsage, programName);
|
||||
}
|
||||
|
||||
// print_usage_and_exit
|
||||
static
|
||||
void
|
||||
print_usage_and_exit(bool error)
|
||||
{
|
||||
print_usage(error);
|
||||
exit(error ? 1 : 0);
|
||||
}
|
||||
|
||||
// get_id
|
||||
static
|
||||
bool
|
||||
get_id(const char *str, int32 &id)
|
||||
{
|
||||
int32 len = strlen(str);
|
||||
for (int32 i = 0; i < len; i++) {
|
||||
if (!isdigit(str[i]))
|
||||
return false;
|
||||
}
|
||||
|
||||
id = atol(str);
|
||||
return true;
|
||||
}
|
||||
|
||||
// load_program
|
||||
thread_id
|
||||
load_program(const char *const *args, int32 argCount)
|
||||
{
|
||||
// TODO: We need to find the program in the PATH, if no absolute or relative
|
||||
// path has been given (i.e. only a name).
|
||||
return load_image(argCount, (const char**)args, (const char**)environ);
|
||||
}
|
||||
|
||||
|
||||
// set_team_debugging_flags
|
||||
static
|
||||
void
|
||||
set_team_debugging_flags(port_id nubPort, int32 flags)
|
||||
{
|
||||
debug_nub_set_team_flags message;
|
||||
message.flags = flags;
|
||||
|
||||
while (true) {
|
||||
status_t error = write_port(nubPort, B_DEBUG_MESSAGE_SET_TEAM_FLAGS,
|
||||
&message, sizeof(message));
|
||||
if (error == B_OK)
|
||||
return;
|
||||
|
||||
if (error != B_INTERRUPTED) {
|
||||
fprintf(stderr, "Failed to set team debug flags: %s\n",
|
||||
strerror(error));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set_thread_debugging_flags
|
||||
static
|
||||
void
|
||||
set_thread_debugging_flags(port_id nubPort, thread_id thread, int32 flags)
|
||||
{
|
||||
debug_nub_set_thread_flags message;
|
||||
message.thread = thread;
|
||||
message.flags = flags;
|
||||
|
||||
while (true) {
|
||||
status_t error = write_port(nubPort, B_DEBUG_MESSAGE_SET_THREAD_FLAGS,
|
||||
&message, sizeof(message));
|
||||
if (error == B_OK)
|
||||
return;
|
||||
|
||||
if (error != B_INTERRUPTED) {
|
||||
fprintf(stderr, "Failed to set thread debug flags: %s\n",
|
||||
strerror(error));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// run_thread
|
||||
static
|
||||
void
|
||||
run_thread(port_id nubPort, thread_id thread)
|
||||
{
|
||||
debug_nub_run_thread message;
|
||||
message.thread = thread;
|
||||
|
||||
while (true) {
|
||||
status_t error = write_port(nubPort, B_DEBUG_MESSAGE_RUN_THREAD,
|
||||
&message, sizeof(message));
|
||||
if (error == B_OK)
|
||||
return;
|
||||
|
||||
if (error != B_INTERRUPTED) {
|
||||
fprintf(stderr, "Failed to run thread %ld: %s\n",
|
||||
thread, strerror(error));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// init_syscalls
|
||||
static
|
||||
void
|
||||
init_syscalls()
|
||||
{
|
||||
// init the syscall vector
|
||||
get_syscalls0(sSyscallVector);
|
||||
get_syscalls1(sSyscallVector);
|
||||
get_syscalls2(sSyscallVector);
|
||||
get_syscalls3(sSyscallVector);
|
||||
get_syscalls4(sSyscallVector);
|
||||
get_syscalls5(sSyscallVector);
|
||||
get_syscalls6(sSyscallVector);
|
||||
get_syscalls7(sSyscallVector);
|
||||
get_syscalls8(sSyscallVector);
|
||||
get_syscalls9(sSyscallVector);
|
||||
get_syscalls10(sSyscallVector);
|
||||
get_syscalls11(sSyscallVector);
|
||||
get_syscalls12(sSyscallVector);
|
||||
get_syscalls13(sSyscallVector);
|
||||
get_syscalls14(sSyscallVector);
|
||||
get_syscalls15(sSyscallVector);
|
||||
get_syscalls16(sSyscallVector);
|
||||
get_syscalls17(sSyscallVector);
|
||||
get_syscalls18(sSyscallVector);
|
||||
get_syscalls19(sSyscallVector);
|
||||
|
||||
// init the syscall map
|
||||
int32 count = sSyscallVector.size();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
Syscall *syscall = sSyscallVector[i];
|
||||
sSyscallMap[syscall->Name()] = syscall;
|
||||
}
|
||||
}
|
||||
|
||||
// print_syscall
|
||||
static
|
||||
void
|
||||
print_syscall(debug_pre_syscall &message, MemoryReader &memoryReader,
|
||||
bool printArguments, bool getContents, bool printReturnValue,
|
||||
bool colorize)
|
||||
{
|
||||
int32 syscallNumber = message.syscall;
|
||||
Syscall *syscall = sSyscallVector[syscallNumber];
|
||||
|
||||
// print syscall name
|
||||
printf("[%6ld] %s(", message.thread, syscall->Name().c_str());
|
||||
|
||||
// print arguments
|
||||
if (printArguments) {
|
||||
int32 count = syscall->CountParameters();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
// get the value
|
||||
Parameter *parameter = syscall->ParameterAt(i);
|
||||
TypeHandler *handler = parameter->Handler();
|
||||
string value = handler->GetParameterValue(
|
||||
(char*)message.args + parameter->Offset(), getContents,
|
||||
memoryReader);
|
||||
|
||||
printf((i > 0 ? ", %s" : "%s"), value.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
printf(") pre\n");
|
||||
}
|
||||
|
||||
// print_syscall
|
||||
static
|
||||
void
|
||||
print_syscall(debug_post_syscall &message, MemoryReader &memoryReader,
|
||||
bool printArguments, bool getContents, bool printReturnValue,
|
||||
bool colorize)
|
||||
{
|
||||
// TODO: colorize support
|
||||
int32 syscallNumber = message.syscall;
|
||||
Syscall *syscall = sSyscallVector[syscallNumber];
|
||||
|
||||
// print syscall name
|
||||
printf("[%6ld] %s(", message.thread, syscall->Name().c_str());
|
||||
|
||||
// print arguments
|
||||
if (printArguments) {
|
||||
int32 count = syscall->CountParameters();
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
// get the value
|
||||
Parameter *parameter = syscall->ParameterAt(i);
|
||||
TypeHandler *handler = parameter->Handler();
|
||||
string value = handler->GetParameterValue(
|
||||
(char*)message.args + parameter->Offset(), getContents,
|
||||
memoryReader);
|
||||
|
||||
printf((i > 0 ? ", %s" : "%s"), value.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
printf(")");
|
||||
|
||||
// print return value
|
||||
if (printReturnValue) {
|
||||
TypeHandler *handler = syscall->ReturnType()->Handler();
|
||||
string value = handler->GetReturnValue(message.return_value,
|
||||
getContents, memoryReader);
|
||||
if (value.length() > 0)
|
||||
printf(" = %s", value.c_str());
|
||||
// TODO: If the return value is a status_t, print the error code.
|
||||
}
|
||||
|
||||
printf(" (%lld us)\n", message.end_time - message.start_time);
|
||||
|
||||
//for (int32 i = 0; i < 16; i++) {
|
||||
// if (i % 4 == 0) {
|
||||
// if (i > 0)
|
||||
// printf("\n");
|
||||
// printf(" ");
|
||||
// } else
|
||||
// printf(" ");
|
||||
// printf("%08lx", message.args[i]);
|
||||
//}
|
||||
//printf("\n");
|
||||
|
||||
}
|
||||
|
||||
|
||||
// main
|
||||
int
|
||||
main(int argc, const char *const *argv)
|
||||
{
|
||||
sArgc = argc;
|
||||
sArgv = argv;
|
||||
|
||||
// parameters
|
||||
const char *const *programArgs = NULL;
|
||||
int32 programArgCount = 0;
|
||||
bool printArguments = true;
|
||||
bool colorize = true;
|
||||
bool fastMode = false;
|
||||
bool printReturnValues = true;
|
||||
bool traceChildThreads = false;
|
||||
bool traceTeam = false;
|
||||
|
||||
// parse arguments
|
||||
for (int argi = 1; argi < argc; argi++) {
|
||||
const char *arg = argv[argi];
|
||||
if (arg[0] == '-') {
|
||||
if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) {
|
||||
print_usage_and_exit(false);
|
||||
} else if (strcmp(arg, "-a") == 0) {
|
||||
printArguments = false;
|
||||
} else if (strcmp(arg, "-c") == 0) {
|
||||
colorize = false;
|
||||
} else if (strcmp(arg, "-f") == 0) {
|
||||
fastMode = true;
|
||||
} else if (strcmp(arg, "-r") == 0) {
|
||||
printReturnValues = false;
|
||||
} else if (strcmp(arg, "-s") == 0) {
|
||||
traceChildThreads = true;
|
||||
} else if (strcmp(arg, "-T") == 0) {
|
||||
traceTeam = true;
|
||||
} else {
|
||||
print_usage_and_exit(true);
|
||||
}
|
||||
} else {
|
||||
programArgs = argv + argi;
|
||||
programArgCount = argc - argi;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// check parameters
|
||||
if (!programArgs)
|
||||
print_usage_and_exit(true);
|
||||
|
||||
// initialize our syscalls vector and map
|
||||
init_syscalls();
|
||||
|
||||
// get thread/team to be debugged
|
||||
thread_id thread = -1;
|
||||
team_id team = -1;
|
||||
if (programArgCount > 1
|
||||
|| !get_id(*programArgs, (traceTeam ? team : thread))) {
|
||||
// we've been given an executable and need to load it
|
||||
thread = load_program(programArgs, programArgCount);
|
||||
}
|
||||
|
||||
// get the team ID, if we have none yet
|
||||
if (team < 0) {
|
||||
thread_info threadInfo;
|
||||
status_t error = get_thread_info(thread, &threadInfo);
|
||||
if (error != B_OK) {
|
||||
fprintf(stderr, "Failed to get info for thread %ld: %s\n", thread,
|
||||
strerror(error));
|
||||
exit(1);
|
||||
}
|
||||
team = threadInfo.team;
|
||||
}
|
||||
|
||||
// create a debugger port
|
||||
port_id debuggerPort = create_port(10, "debugger port");
|
||||
if (debuggerPort < 0) {
|
||||
fprintf(stderr, "Failed to create debugger port: %s\n",
|
||||
strerror(debuggerPort));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// install ourselves as the team debugger
|
||||
port_id nubPort = install_team_debugger(team, debuggerPort);
|
||||
if (nubPort < 0) {
|
||||
fprintf(stderr, "Failed to install team debugger: %s\n",
|
||||
strerror(nubPort));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// set team debugging flags
|
||||
int32 teamDebugFlags
|
||||
= (printArguments ? 0 : B_TEAM_DEBUG_SYSCALL_FAST_TRACE)
|
||||
| (traceTeam ? B_TEAM_DEBUG_POST_SYSCALL : 0);
|
||||
set_team_debugging_flags(nubPort, teamDebugFlags);
|
||||
|
||||
// set thread debugging flags
|
||||
if (thread >= 0) {
|
||||
int32 threadDebugFlags = 0;
|
||||
if (!traceTeam) {
|
||||
threadDebugFlags = B_THREAD_DEBUG_POST_SYSCALL
|
||||
| (traceChildThreads
|
||||
? B_THREAD_DEBUG_SYSCALL_TRACE_CHILD_THREADS : 0);
|
||||
}
|
||||
set_thread_debugging_flags(nubPort, thread, threadDebugFlags);
|
||||
|
||||
// resume the target thread to be sure, it's running
|
||||
resume_thread(thread);
|
||||
}
|
||||
|
||||
MemoryReader memoryReader(nubPort);
|
||||
|
||||
// debug loop
|
||||
while (true) {
|
||||
int32 code;
|
||||
debug_debugger_message_data message;
|
||||
ssize_t messageSize = read_port(debuggerPort, &code, &message,
|
||||
sizeof(message));
|
||||
|
||||
if (messageSize < 0) {
|
||||
if (messageSize == B_INTERRUPTED)
|
||||
continue;
|
||||
|
||||
fprintf(stderr, "Reading from debugger port failed: %s\n",
|
||||
strerror(messageSize));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
thread_id concernedThread = -1;
|
||||
switch (code) {
|
||||
case B_DEBUGGER_MESSAGE_THREAD_STOPPED:
|
||||
concernedThread = message.thread_stopped.thread;
|
||||
printf("B_DEBUGGER_MESSAGE_THREAD_STOPPED: thread: %ld\n", concernedThread);
|
||||
break;
|
||||
case B_DEBUGGER_MESSAGE_PRE_SYSCALL:
|
||||
{
|
||||
concernedThread = message.pre_syscall.thread;
|
||||
//printf("B_DEBUGGER_MESSAGE_PRE_SYSCALL: thread: %ld\n", concernedThread);
|
||||
print_syscall(message.pre_syscall, memoryReader,
|
||||
printArguments, !fastMode, printReturnValues, colorize);
|
||||
|
||||
break;
|
||||
}
|
||||
case B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED:
|
||||
concernedThread = message.signal_received.thread;
|
||||
printf("B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED: thread: %ld\n", concernedThread);
|
||||
break;
|
||||
case B_DEBUGGER_MESSAGE_POST_SYSCALL:
|
||||
{
|
||||
concernedThread = message.post_syscall.thread;
|
||||
print_syscall(message.post_syscall, memoryReader,
|
||||
printArguments, !fastMode, printReturnValues, colorize);
|
||||
|
||||
break;
|
||||
}
|
||||
case B_DEBUGGER_MESSAGE_TEAM_DELETED:
|
||||
{
|
||||
printf("B_DEBUGGER_MESSAGE_TEAM_DELETED: team: %ld\n",
|
||||
message.team_deleted.team);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
// tell the thread to continue
|
||||
if (concernedThread >= 0) {
|
||||
run_thread(nubPort, concernedThread);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright 2005, Ingo Weinhold, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include <syscalls.h>
|
||||
|
||||
#include "Syscall.h"
|
||||
#include "TypeHandler.h"
|
||||
|
||||
#include "strace_syscalls.h"
|
||||
// generated by gensyscalls
|
||||
|
||||
Reference in New Issue
Block a user