* debug_create_symbol_lookup_context() gets a team ID instead of a
debug context now. That's all it needs. * Added the option "-a" to the profile command line tool. It triggers profiling of the whole system. There are still some issues, particularly image related ones. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30129 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
2ad2768adc
commit
0f37915687
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2005, Ingo Weinhold, bonefish@users.sf.net.
|
* Copyright 2005-2009, Ingo Weinhold, bonefish@users.sf.net.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
#ifndef _DEBUG_SUPPORT_H
|
#ifndef _DEBUG_SUPPORT_H
|
||||||
@ -57,7 +57,7 @@ status_t debug_get_stack_frame(debug_context *context,
|
|||||||
typedef struct debug_symbol_lookup_context debug_symbol_lookup_context;
|
typedef struct debug_symbol_lookup_context debug_symbol_lookup_context;
|
||||||
typedef struct debug_symbol_iterator debug_symbol_iterator;
|
typedef struct debug_symbol_iterator debug_symbol_iterator;
|
||||||
|
|
||||||
status_t debug_create_symbol_lookup_context(debug_context *debugContext,
|
status_t debug_create_symbol_lookup_context(team_id team,
|
||||||
debug_symbol_lookup_context **lookupContext);
|
debug_symbol_lookup_context **lookupContext);
|
||||||
void debug_delete_symbol_lookup_context(
|
void debug_delete_symbol_lookup_context(
|
||||||
debug_symbol_lookup_context *lookupContext);
|
debug_symbol_lookup_context *lookupContext);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
|
* Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
#ifndef OPTIONS_H
|
#ifndef OPTIONS_H
|
||||||
@ -17,6 +17,7 @@ struct Options {
|
|||||||
stack_depth(5),
|
stack_depth(5),
|
||||||
output(NULL),
|
output(NULL),
|
||||||
callgrind_directory(NULL),
|
callgrind_directory(NULL),
|
||||||
|
profile_all(false),
|
||||||
profile_kernel(true),
|
profile_kernel(true),
|
||||||
profile_loading(false),
|
profile_loading(false),
|
||||||
profile_teams(true),
|
profile_teams(true),
|
||||||
@ -29,6 +30,7 @@ struct Options {
|
|||||||
int32 stack_depth;
|
int32 stack_depth;
|
||||||
FILE* output;
|
FILE* output;
|
||||||
const char* callgrind_directory;
|
const char* callgrind_directory;
|
||||||
|
bool profile_all;
|
||||||
bool profile_kernel;
|
bool profile_kernel;
|
||||||
bool profile_loading;
|
bool profile_loading;
|
||||||
bool profile_teams;
|
bool profile_teams;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
|
* Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -10,12 +10,21 @@
|
|||||||
#include <image.h>
|
#include <image.h>
|
||||||
|
|
||||||
#include <debug_support.h>
|
#include <debug_support.h>
|
||||||
|
#include <system_profiler_defs.h>
|
||||||
|
|
||||||
#include "debug_utils.h"
|
#include "debug_utils.h"
|
||||||
|
|
||||||
#include "Options.h"
|
#include "Options.h"
|
||||||
|
|
||||||
|
|
||||||
|
//#define TRACE_PROFILE_TEAM
|
||||||
|
#ifdef TRACE_PROFILE_TEAM
|
||||||
|
# define TRACE(x...) printf(x)
|
||||||
|
#else
|
||||||
|
# define TRACE(x...) do {} while(false)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
SAMPLE_AREA_SIZE = 128 * 1024,
|
SAMPLE_AREA_SIZE = 128 * 1024,
|
||||||
};
|
};
|
||||||
@ -71,8 +80,7 @@ Team::Init(team_id teamID, port_id debuggerPort)
|
|||||||
|
|
||||||
// create symbol lookup context
|
// create symbol lookup context
|
||||||
debug_symbol_lookup_context* lookupContext;
|
debug_symbol_lookup_context* lookupContext;
|
||||||
error = debug_create_symbol_lookup_context(&fDebugContext,
|
error = debug_create_symbol_lookup_context(ID(), &lookupContext);
|
||||||
&lookupContext);
|
|
||||||
if (error != B_OK) {
|
if (error != B_OK) {
|
||||||
fprintf(stderr, "%s: Failed to create symbol lookup context for "
|
fprintf(stderr, "%s: Failed to create symbol lookup context for "
|
||||||
"team %ld: %s\n", kCommandName, teamID, strerror(error));
|
"team %ld: %s\n", kCommandName, teamID, strerror(error));
|
||||||
@ -87,14 +95,8 @@ Team::Init(team_id teamID, port_id debuggerPort)
|
|||||||
|
|
||||||
// also try to load the kernel images and symbols
|
// also try to load the kernel images and symbols
|
||||||
if (gOptions.profile_kernel) {
|
if (gOptions.profile_kernel) {
|
||||||
// fake a debug context -- it's not really needed anyway
|
|
||||||
debug_context debugContext;
|
|
||||||
debugContext.team = B_SYSTEM_TEAM;
|
|
||||||
debugContext.nub_port = -1;
|
|
||||||
debugContext.reply_port = -1;
|
|
||||||
|
|
||||||
// create symbol lookup context
|
// create symbol lookup context
|
||||||
error = debug_create_symbol_lookup_context(&debugContext,
|
error = debug_create_symbol_lookup_context(B_SYSTEM_TEAM,
|
||||||
&lookupContext);
|
&lookupContext);
|
||||||
if (error != B_OK) {
|
if (error != B_OK) {
|
||||||
fprintf(stderr, "%s: Failed to create symbol lookup context "
|
fprintf(stderr, "%s: Failed to create symbol lookup context "
|
||||||
@ -116,9 +118,20 @@ Team::Init(team_id teamID, port_id debuggerPort)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Team::Init(system_profiler_team_added* addedInfo)
|
||||||
|
{
|
||||||
|
fInfo.team = addedInfo->team;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
Team::InitThread(Thread* thread)
|
Team::InitThread(Thread* thread)
|
||||||
{
|
{
|
||||||
|
// The thread
|
||||||
|
thread->ProfileResult()->SetLazyImages(!_SynchronousProfiling());
|
||||||
|
|
||||||
// create the sample area
|
// create the sample area
|
||||||
char areaName[B_OS_NAME_LENGTH];
|
char areaName[B_OS_NAME_LENGTH];
|
||||||
snprintf(areaName, sizeof(areaName), "profiling samples %ld",
|
snprintf(areaName, sizeof(areaName), "profiling samples %ld",
|
||||||
@ -142,41 +155,47 @@ Team::InitThread(Thread* thread)
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set thread debugging flags and start profiling
|
if (!_SynchronousProfiling()) {
|
||||||
int32 threadDebugFlags = 0;
|
// set thread debugging flags and start profiling
|
||||||
// if (!traceTeam) {
|
int32 threadDebugFlags = 0;
|
||||||
// threadDebugFlags = B_THREAD_DEBUG_POST_SYSCALL
|
// if (!traceTeam) {
|
||||||
// | (traceChildThreads
|
// threadDebugFlags = B_THREAD_DEBUG_POST_SYSCALL
|
||||||
// ? B_THREAD_DEBUG_SYSCALL_TRACE_CHILD_THREADS : 0);
|
// | (traceChildThreads
|
||||||
// }
|
// ? B_THREAD_DEBUG_SYSCALL_TRACE_CHILD_THREADS : 0);
|
||||||
set_thread_debugging_flags(fNubPort, thread->ID(), threadDebugFlags);
|
// }
|
||||||
|
set_thread_debugging_flags(fNubPort, thread->ID(), threadDebugFlags);
|
||||||
|
|
||||||
// start profiling
|
// start profiling
|
||||||
debug_nub_start_profiler message;
|
debug_nub_start_profiler message;
|
||||||
message.reply_port = fDebugContext.reply_port;
|
message.reply_port = fDebugContext.reply_port;
|
||||||
message.thread = thread->ID();
|
message.thread = thread->ID();
|
||||||
message.interval = gOptions.interval;
|
message.interval = gOptions.interval;
|
||||||
message.sample_area = sampleArea;
|
message.sample_area = sampleArea;
|
||||||
message.stack_depth = gOptions.stack_depth;
|
message.stack_depth = gOptions.stack_depth;
|
||||||
message.variable_stack_depth = gOptions.analyze_full_stack;
|
message.variable_stack_depth = gOptions.analyze_full_stack;
|
||||||
|
|
||||||
debug_nub_start_profiler_reply reply;
|
debug_nub_start_profiler_reply reply;
|
||||||
status_t error = send_debug_message(&fDebugContext,
|
status_t error = send_debug_message(&fDebugContext,
|
||||||
B_DEBUG_START_PROFILER, &message, sizeof(message), &reply,
|
B_DEBUG_START_PROFILER, &message, sizeof(message), &reply,
|
||||||
sizeof(reply));
|
sizeof(reply));
|
||||||
if (error != B_OK || (error = reply.error) != B_OK) {
|
if (error != B_OK || (error = reply.error) != B_OK) {
|
||||||
fprintf(stderr, "%s: Failed to start profiler for thread %ld: %s\n",
|
fprintf(stderr, "%s: Failed to start profiler for thread %ld: %s\n",
|
||||||
kCommandName, thread->ID(), strerror(error));
|
kCommandName, thread->ID(), strerror(error));
|
||||||
return error;
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
thread->SetInterval(reply.interval);
|
||||||
|
|
||||||
|
fThreads.Add(thread);
|
||||||
|
|
||||||
|
// resume the target thread to be sure, it's running
|
||||||
|
resume_thread(thread->ID());
|
||||||
|
} else {
|
||||||
|
// debugger-less profiling
|
||||||
|
thread->SetInterval(gOptions.interval);
|
||||||
|
fThreads.Add(thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
thread->SetInterval(reply.interval);
|
|
||||||
|
|
||||||
fThreads.Add(thread);
|
|
||||||
|
|
||||||
// resume the target thread to be sure, it's running
|
|
||||||
resume_thread(thread->ID());
|
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,20 +230,19 @@ Team::Exec(int32 event)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
Team::AddImage(const image_info& imageInfo, int32 event)
|
Team::AddImage(const image_info& imageInfo, team_id owner, int32 event)
|
||||||
{
|
{
|
||||||
// create symbol lookup context
|
// create symbol lookup context
|
||||||
debug_symbol_lookup_context* lookupContext;
|
debug_symbol_lookup_context* lookupContext;
|
||||||
status_t error = debug_create_symbol_lookup_context(&fDebugContext,
|
status_t error = debug_create_symbol_lookup_context(owner, &lookupContext);
|
||||||
&lookupContext);
|
|
||||||
if (error != B_OK) {
|
if (error != B_OK) {
|
||||||
fprintf(stderr, "%s: Failed to create symbol lookup context for "
|
fprintf(stderr, "%s: Failed to create symbol lookup context for "
|
||||||
"team %ld: %s\n", kCommandName, ID(), strerror(error));
|
"team %ld: %s\n", kCommandName, owner, strerror(error));
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
Image* image;
|
Image* image;
|
||||||
error = _LoadImageSymbols(lookupContext, imageInfo, ID(), event,
|
error = _LoadImageSymbols(lookupContext, imageInfo, owner, event,
|
||||||
&image);
|
&image);
|
||||||
debug_delete_symbol_lookup_context(lookupContext);
|
debug_delete_symbol_lookup_context(lookupContext);
|
||||||
|
|
||||||
@ -242,10 +260,10 @@ Team::AddImage(const image_info& imageInfo, int32 event)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
Team::RemoveImage(const image_info& imageInfo, int32 event)
|
Team::RemoveImage(image_id imageID, int32 event)
|
||||||
{
|
{
|
||||||
for (int32 i = 0; Image* image = fImages.ItemAt(i); i++) {
|
for (int32 i = 0; Image* image = fImages.ItemAt(i); i++) {
|
||||||
if (image->ID() == imageInfo.id) {
|
if (image->ID() == imageID) {
|
||||||
_RemoveImage(i, event);
|
_RemoveImage(i, event);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
@ -295,10 +313,14 @@ Team::_LoadImageSymbols(debug_symbol_lookup_context* lookupContext,
|
|||||||
|
|
||||||
status_t error = image->LoadSymbols(lookupContext);
|
status_t error = image->LoadSymbols(lookupContext);
|
||||||
if (error != B_OK) {
|
if (error != B_OK) {
|
||||||
|
TRACE("Failed to load symbols of image %ld: %s\n", image->ID(),
|
||||||
|
strerror(error));
|
||||||
delete image;
|
delete image;
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TRACE("image %ld: loaded %ld symbols\n", image->ID(), image->SymbolCount());
|
||||||
|
|
||||||
if (!fImages.AddItem(image)) {
|
if (!fImages.AddItem(image)) {
|
||||||
delete image;
|
delete image;
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
@ -318,10 +340,16 @@ Team::_RemoveImage(int32 index, int32 event)
|
|||||||
if (image == NULL)
|
if (image == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Note: We don't tell the threads that the image has been removed. They
|
if (_SynchronousProfiling()) {
|
||||||
// will be updated lazily when their next profiler update arrives. This
|
ThreadList::Iterator it = fThreads.GetIterator();
|
||||||
// is necessary, since the update might contain samples hitting that
|
while (Thread* thread = it.Next())
|
||||||
// image.
|
thread->ProfileResult()->RemoveImage(image);
|
||||||
|
} else {
|
||||||
|
// Note: We don't tell the threads that the image has been removed. They
|
||||||
|
// will be updated lazily when their next profiler update arrives. This
|
||||||
|
// is necessary, since the update might contain samples hitting that
|
||||||
|
// image.
|
||||||
|
}
|
||||||
|
|
||||||
image->SetDeletionEvent(event);
|
image->SetDeletionEvent(event);
|
||||||
image->RemoveReference();
|
image->RemoveReference();
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
|
* Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
#ifndef TEAM_H
|
#ifndef TEAM_H
|
||||||
@ -12,12 +12,16 @@
|
|||||||
#include "Thread.h"
|
#include "Thread.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct system_profiler_team_added;
|
||||||
|
|
||||||
|
|
||||||
class Team {
|
class Team {
|
||||||
public:
|
public:
|
||||||
Team();
|
Team();
|
||||||
~Team();
|
~Team();
|
||||||
|
|
||||||
status_t Init(team_id teamID, port_id debuggerPort);
|
status_t Init(team_id teamID, port_id debuggerPort);
|
||||||
|
status_t Init(system_profiler_team_added* addedInfo);
|
||||||
status_t InitThread(Thread* thread);
|
status_t InitThread(Thread* thread);
|
||||||
|
|
||||||
void RemoveThread(Thread* thread);
|
void RemoveThread(Thread* thread);
|
||||||
@ -25,9 +29,8 @@ public:
|
|||||||
void Exec(int32 event);
|
void Exec(int32 event);
|
||||||
|
|
||||||
status_t AddImage(const image_info& imageInfo,
|
status_t AddImage(const image_info& imageInfo,
|
||||||
int32 event);
|
team_id owner, int32 event);
|
||||||
status_t RemoveImage(const image_info& imageInfo,
|
status_t RemoveImage(image_id imageID, int32 event);
|
||||||
int32 event);
|
|
||||||
|
|
||||||
inline const BObjectList<Image>& Images() const;
|
inline const BObjectList<Image>& Images() const;
|
||||||
Image* FindImage(image_id id) const;
|
Image* FindImage(image_id id) const;
|
||||||
@ -44,6 +47,9 @@ private:
|
|||||||
int32 event, Image** _image = NULL);
|
int32 event, Image** _image = NULL);
|
||||||
void _RemoveImage(int32 index, int32 event);
|
void _RemoveImage(int32 index, int32 event);
|
||||||
|
|
||||||
|
bool _SynchronousProfiling() const
|
||||||
|
{ return fDebugContext.nub_port < 0; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef DoublyLinkedList<Thread> ThreadList;
|
typedef DoublyLinkedList<Thread> ThreadList;
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
|
* Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -96,13 +96,6 @@ Thread::SetInterval(bigtime_t interval)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
|
||||||
Thread::AddImage(Image* image)
|
|
||||||
{
|
|
||||||
return fProfileResult->AddImage(image);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Thread::AddSamples(int32 count, int32 dropped, int32 stackDepth,
|
Thread::AddSamples(int32 count, int32 dropped, int32 stackDepth,
|
||||||
bool variableStackDepth, int32 event)
|
bool variableStackDepth, int32 event)
|
||||||
@ -146,6 +139,13 @@ Thread::AddSamples(int32 count, int32 dropped, int32 stackDepth,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Thread::AddSamples(addr_t* samples, int32 sampleCount)
|
||||||
|
{
|
||||||
|
fProfileResult->AddSamples(samples, sampleCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Thread::PrintResults() const
|
Thread::PrintResults() const
|
||||||
{
|
{
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
|
* Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
#ifndef THREAD_H
|
#ifndef THREAD_H
|
||||||
@ -53,11 +53,13 @@ public:
|
|||||||
void SetSampleArea(area_id area, addr_t* samples);
|
void SetSampleArea(area_id area, addr_t* samples);
|
||||||
void SetInterval(bigtime_t interval);
|
void SetInterval(bigtime_t interval);
|
||||||
|
|
||||||
status_t AddImage(Image* image);
|
inline status_t AddImage(Image* image);
|
||||||
|
inline void RemoveImage(Image* image);
|
||||||
|
|
||||||
void AddSamples(int32 count, int32 dropped,
|
void AddSamples(int32 count, int32 dropped,
|
||||||
int32 stackDepth, bool variableStackDepth,
|
int32 stackDepth, bool variableStackDepth,
|
||||||
int32 event);
|
int32 event);
|
||||||
|
void AddSamples(addr_t* samples, int32 sampleCount);
|
||||||
void PrintResults() const;
|
void PrintResults() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -81,7 +83,10 @@ public:
|
|||||||
|
|
||||||
void SetInterval(bigtime_t interval);
|
void SetInterval(bigtime_t interval);
|
||||||
|
|
||||||
|
virtual void SetLazyImages(bool lazy) = 0;
|
||||||
|
|
||||||
virtual status_t AddImage(Image* image) = 0;
|
virtual status_t AddImage(Image* image) = 0;
|
||||||
|
virtual void RemoveImage(Image* image) = 0;
|
||||||
virtual void SynchronizeImages(int32 event) = 0;
|
virtual void SynchronizeImages(int32 event) = 0;
|
||||||
|
|
||||||
virtual void AddSamples(addr_t* samples,
|
virtual void AddSamples(addr_t* samples,
|
||||||
@ -101,7 +106,10 @@ public:
|
|||||||
AbstractThreadProfileResult();
|
AbstractThreadProfileResult();
|
||||||
virtual ~AbstractThreadProfileResult();
|
virtual ~AbstractThreadProfileResult();
|
||||||
|
|
||||||
|
virtual void SetLazyImages(bool lazy);
|
||||||
|
|
||||||
virtual status_t AddImage(Image* image);
|
virtual status_t AddImage(Image* image);
|
||||||
|
virtual void RemoveImage(Image* image);
|
||||||
virtual void SynchronizeImages(int32 event);
|
virtual void SynchronizeImages(int32 event);
|
||||||
|
|
||||||
ThreadImageType* FindImage(addr_t address) const;
|
ThreadImageType* FindImage(addr_t address) const;
|
||||||
@ -120,6 +128,7 @@ protected:
|
|||||||
ImageList fImages;
|
ImageList fImages;
|
||||||
ImageList fNewImages;
|
ImageList fNewImages;
|
||||||
ImageList fOldImages;
|
ImageList fOldImages;
|
||||||
|
bool fLazyImages;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -192,6 +201,20 @@ Thread::ProfileResult() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Thread::AddImage(Image* image)
|
||||||
|
{
|
||||||
|
return fProfileResult->AddImage(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Thread::RemoveImage(Image* image)
|
||||||
|
{
|
||||||
|
fProfileResult->RemoveImage(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - AbstractThreadProfileResult
|
// #pragma mark - AbstractThreadProfileResult
|
||||||
|
|
||||||
|
|
||||||
@ -200,7 +223,8 @@ AbstractThreadProfileResult<ThreadImageType>::AbstractThreadProfileResult()
|
|||||||
:
|
:
|
||||||
fImages(),
|
fImages(),
|
||||||
fNewImages(),
|
fNewImages(),
|
||||||
fOldImages()
|
fOldImages(),
|
||||||
|
fLazyImages(true)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,6 +239,14 @@ AbstractThreadProfileResult<ThreadImageType>::~AbstractThreadProfileResult()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename ThreadImageType>
|
||||||
|
void
|
||||||
|
AbstractThreadProfileResult<ThreadImageType>::SetLazyImages(bool lazy)
|
||||||
|
{
|
||||||
|
fLazyImages = lazy;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename ThreadImageType>
|
template<typename ThreadImageType>
|
||||||
status_t
|
status_t
|
||||||
AbstractThreadProfileResult<ThreadImageType>::AddImage(Image* image)
|
AbstractThreadProfileResult<ThreadImageType>::AddImage(Image* image)
|
||||||
@ -229,12 +261,33 @@ AbstractThreadProfileResult<ThreadImageType>::AddImage(Image* image)
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
fNewImages.Add(threadImage);
|
if (fLazyImages)
|
||||||
|
fNewImages.Add(threadImage);
|
||||||
|
else
|
||||||
|
fImages.Add(threadImage);
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename ThreadImageType>
|
||||||
|
void
|
||||||
|
AbstractThreadProfileResult<ThreadImageType>::RemoveImage(Image* image)
|
||||||
|
{
|
||||||
|
typename ImageList::Iterator it = fImages.GetIterator();
|
||||||
|
while (ThreadImageType* threadImage = it.Next()) {
|
||||||
|
if (threadImage->GetImage() == image) {
|
||||||
|
it.Remove();
|
||||||
|
if (threadImage->TotalHits() > 0)
|
||||||
|
fOldImages.Add(threadImage);
|
||||||
|
else
|
||||||
|
delete threadImage;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename ThreadImageType>
|
template<typename ThreadImageType>
|
||||||
void
|
void
|
||||||
AbstractThreadProfileResult<ThreadImageType>::SynchronizeImages(int32 event)
|
AbstractThreadProfileResult<ThreadImageType>::SynchronizeImages(int32 event)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
|
* Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -17,6 +17,9 @@
|
|||||||
#include <OS.h>
|
#include <OS.h>
|
||||||
#include <String.h>
|
#include <String.h>
|
||||||
|
|
||||||
|
#include <syscalls.h>
|
||||||
|
#include <system_profiler_defs.h>
|
||||||
|
|
||||||
#include <debug_support.h>
|
#include <debug_support.h>
|
||||||
#include <ObjectList.h>
|
#include <ObjectList.h>
|
||||||
#include <Referenceable.h>
|
#include <Referenceable.h>
|
||||||
@ -31,6 +34,10 @@
|
|||||||
#include "Team.h"
|
#include "Team.h"
|
||||||
|
|
||||||
|
|
||||||
|
// size of the sample buffer area for system profiling
|
||||||
|
#define PROFILE_ALL_SAMPLE_AREA_SIZE (4 * 1024 * 1024)
|
||||||
|
|
||||||
|
|
||||||
extern const char* __progname;
|
extern const char* __progname;
|
||||||
const char* kCommandName = __progname;
|
const char* kCommandName = __progname;
|
||||||
|
|
||||||
@ -41,12 +48,15 @@ class Thread;
|
|||||||
|
|
||||||
|
|
||||||
static const char* kUsage =
|
static const char* kUsage =
|
||||||
"Usage: %s [ <options> ] <command line>\n"
|
"Usage: %s [ <options> ] [ <command line> ]\n"
|
||||||
"Executes the given command line <command line> and periodically samples\n"
|
"Profiles threads by periodically sampling the program counter. There are\n"
|
||||||
"all started threads' program counters. When a thread terminates, a list\n"
|
"two different modes: One profiles the complete system. The other starts\n"
|
||||||
"of the functions where the thread was encountered is printed.\n"
|
"a program and profiles that and (optionally) its children. When a thread\n"
|
||||||
|
"terminates, a list of the functions where the thread was encountered is\n"
|
||||||
|
"printed.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Options:\n"
|
"Options:\n"
|
||||||
|
" -a, --all - Profile all teams.\n"
|
||||||
" -c - Don't profile child threads. Default is to\n"
|
" -c - Don't profile child threads. Default is to\n"
|
||||||
" recursively profile all threads created by a profiled\n"
|
" recursively profile all threads created by a profiled\n"
|
||||||
" thread.\n"
|
" thread.\n"
|
||||||
@ -75,6 +85,8 @@ static const char* kUsage =
|
|||||||
|
|
||||||
Options gOptions;
|
Options gOptions;
|
||||||
|
|
||||||
|
static bool sCaughtDeadlySignal = false;
|
||||||
|
|
||||||
|
|
||||||
class ThreadManager {
|
class ThreadManager {
|
||||||
public:
|
public:
|
||||||
@ -88,25 +100,12 @@ public:
|
|||||||
|
|
||||||
status_t AddTeam(team_id teamID, Team** _team = NULL)
|
status_t AddTeam(team_id teamID, Team** _team = NULL)
|
||||||
{
|
{
|
||||||
if (FindTeam(teamID) != NULL)
|
return _AddTeam(teamID, NULL, _team);
|
||||||
return B_BAD_VALUE;
|
}
|
||||||
|
|
||||||
Team* team = new(std::nothrow) Team;
|
status_t AddTeam(system_profiler_team_added* addedInfo, Team** _team = NULL)
|
||||||
if (team == NULL)
|
{
|
||||||
return B_NO_MEMORY;
|
return _AddTeam(addedInfo->team, addedInfo, _team);
|
||||||
|
|
||||||
status_t error = team->Init(teamID, fDebuggerPort);
|
|
||||||
if (error != B_OK) {
|
|
||||||
delete team;
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
fTeams.AddItem(team);
|
|
||||||
|
|
||||||
if (_team != NULL)
|
|
||||||
*_team = team;
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t AddThread(thread_id threadID)
|
status_t AddThread(thread_id threadID)
|
||||||
@ -175,7 +174,73 @@ public:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32 CountThreads() const
|
||||||
|
{
|
||||||
|
return fThreads.CountItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
Thread* ThreadAt(int32 index) const
|
||||||
|
{
|
||||||
|
return fThreads.ItemAt(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t AddImage(team_id teamID, const image_info& imageInfo, int32 event)
|
||||||
|
{
|
||||||
|
if (teamID == B_SYSTEM_TEAM) {
|
||||||
|
// a kernel image -- add it to all teams
|
||||||
|
int32 count = fTeams.CountItems();
|
||||||
|
for (int32 i = 0; i < count; i++)
|
||||||
|
fTeams.ItemAt(i)->AddImage(imageInfo, teamID, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
// a userland team image -- add it to that image
|
||||||
|
if (Team* team = FindTeam(teamID))
|
||||||
|
return team->AddImage(imageInfo, teamID, event);
|
||||||
|
|
||||||
|
return B_BAD_TEAM_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoveImage(team_id teamID, image_id imageID, int32 event)
|
||||||
|
{
|
||||||
|
if (teamID == B_SYSTEM_TEAM) {
|
||||||
|
// a kernel image -- remove it from all teams
|
||||||
|
int32 count = fTeams.CountItems();
|
||||||
|
for (int32 i = 0; i < count; i++)
|
||||||
|
fTeams.ItemAt(i)->RemoveImage(imageID, event);
|
||||||
|
} else {
|
||||||
|
// a userland team image -- add it to that image
|
||||||
|
if (Team* team = FindTeam(teamID))
|
||||||
|
team->RemoveImage(imageID, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
status_t _AddTeam(team_id teamID, system_profiler_team_added* addedInfo,
|
||||||
|
Team** _team = NULL)
|
||||||
|
{
|
||||||
|
if (FindTeam(teamID) != NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
Team* team = new(std::nothrow) Team;
|
||||||
|
if (team == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
status_t error = addedInfo != NULL
|
||||||
|
? team->Init(addedInfo)
|
||||||
|
: team->Init(teamID, fDebuggerPort);
|
||||||
|
if (error != B_OK) {
|
||||||
|
delete team;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
fTeams.AddItem(team);
|
||||||
|
|
||||||
|
if (_team != NULL)
|
||||||
|
*_team = team;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
status_t _CreateThreadProfileResult(Thread* thread)
|
status_t _CreateThreadProfileResult(Thread* thread)
|
||||||
{
|
{
|
||||||
ThreadProfileResult* profileResult;
|
ThreadProfileResult* profileResult;
|
||||||
@ -231,6 +296,211 @@ get_id(const char *str, int32 &id)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
process_event_buffer(ThreadManager& threadManager, uint8* buffer,
|
||||||
|
size_t bufferSize)
|
||||||
|
{
|
||||||
|
//printf("process_event_buffer(%p, %lu)\n", buffer, bufferSize);
|
||||||
|
const uint8* bufferEnd = buffer + bufferSize;
|
||||||
|
|
||||||
|
while (buffer < bufferEnd) {
|
||||||
|
system_profiler_event_header* header
|
||||||
|
= (system_profiler_event_header*)buffer;
|
||||||
|
|
||||||
|
buffer += sizeof(system_profiler_event_header);
|
||||||
|
|
||||||
|
switch (header->event) {
|
||||||
|
case B_SYSTEM_PROFILER_TEAM_ADDED:
|
||||||
|
{
|
||||||
|
system_profiler_team_added* event
|
||||||
|
= (system_profiler_team_added*)buffer;
|
||||||
|
|
||||||
|
threadManager.AddTeam(event);
|
||||||
|
// TODO: ATM we're not adding kernel images to the team, if this is a team
|
||||||
|
// created after we started profiling!
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case B_SYSTEM_PROFILER_TEAM_REMOVED:
|
||||||
|
{
|
||||||
|
system_profiler_team_removed* event
|
||||||
|
= (system_profiler_team_removed*)buffer;
|
||||||
|
|
||||||
|
// TODO: Print results!
|
||||||
|
threadManager.RemoveTeam(event->team);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case B_SYSTEM_PROFILER_TEAM_EXEC:
|
||||||
|
{
|
||||||
|
system_profiler_team_exec* event
|
||||||
|
= (system_profiler_team_exec*)event;
|
||||||
|
|
||||||
|
if (Team* team = threadManager.FindTeam(event->team))
|
||||||
|
team->Exec(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case B_SYSTEM_PROFILER_THREAD_ADDED:
|
||||||
|
{
|
||||||
|
system_profiler_thread_added* event
|
||||||
|
= (system_profiler_thread_added*)buffer;
|
||||||
|
|
||||||
|
threadManager.AddThread(event->thread);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case B_SYSTEM_PROFILER_THREAD_REMOVED:
|
||||||
|
{
|
||||||
|
system_profiler_thread_removed* event
|
||||||
|
= (system_profiler_thread_removed*)buffer;
|
||||||
|
|
||||||
|
if (Thread* thread = threadManager.FindThread(event->thread)) {
|
||||||
|
thread->PrintResults();
|
||||||
|
threadManager.RemoveThread(event->thread);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case B_SYSTEM_PROFILER_IMAGE_ADDED:
|
||||||
|
{
|
||||||
|
system_profiler_image_added* event
|
||||||
|
= (system_profiler_image_added*)buffer;
|
||||||
|
|
||||||
|
threadManager.AddImage(event->team, event->info, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case B_SYSTEM_PROFILER_IMAGE_REMOVED:
|
||||||
|
{
|
||||||
|
system_profiler_image_removed* event
|
||||||
|
= (system_profiler_image_removed*)buffer;
|
||||||
|
|
||||||
|
threadManager.RemoveImage(event->team, event->image, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case B_SYSTEM_PROFILER_SAMPLES:
|
||||||
|
{
|
||||||
|
system_profiler_samples* event
|
||||||
|
= (system_profiler_samples*)buffer;
|
||||||
|
|
||||||
|
Thread* thread = threadManager.FindThread(event->thread);
|
||||||
|
if (thread != NULL) {
|
||||||
|
thread->AddSamples(event->samples,
|
||||||
|
(addr_t*)(buffer + header->size) - event->samples);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case B_SYSTEM_PROFILER_SAMPLES_END:
|
||||||
|
{
|
||||||
|
// Marks the end of the ring buffer -- we need to ignore the
|
||||||
|
// remaining bytes.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer += header->size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
signal_handler(int signal, void* data)
|
||||||
|
{
|
||||||
|
sCaughtDeadlySignal = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
profile_all()
|
||||||
|
{
|
||||||
|
// install signal handlers so we can exit gracefully
|
||||||
|
struct sigaction action;
|
||||||
|
action.sa_handler = (sighandler_t)signal_handler;
|
||||||
|
sigemptyset(&action.sa_mask);
|
||||||
|
action.sa_userdata = NULL;
|
||||||
|
if (sigaction(SIGHUP, &action, NULL) < 0
|
||||||
|
|| sigaction(SIGINT, &action, NULL) < 0
|
||||||
|
|| sigaction(SIGQUIT, &action, NULL) < 0) {
|
||||||
|
fprintf(stderr, "%s: Failed to install signal handlers: %s\n",
|
||||||
|
kCommandName, strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create and area for the sample buffer
|
||||||
|
system_profiler_buffer_header* bufferHeader;
|
||||||
|
area_id area = create_area("profiling buffer", (void**)&bufferHeader,
|
||||||
|
B_ANY_ADDRESS, PROFILE_ALL_SAMPLE_AREA_SIZE, B_NO_LOCK, B_READ_AREA);
|
||||||
|
if (area < 0) {
|
||||||
|
fprintf(stderr, "%s: Failed to create sample area: %s\n", kCommandName,
|
||||||
|
strerror(area));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8* bufferBase = (uint8*)(bufferHeader + 1);
|
||||||
|
size_t totalBufferSize = PROFILE_ALL_SAMPLE_AREA_SIZE
|
||||||
|
- (bufferBase - (uint8*)bufferHeader);
|
||||||
|
|
||||||
|
// create a thread manager
|
||||||
|
ThreadManager threadManager(-1); // TODO: We don't need a debugger port!
|
||||||
|
|
||||||
|
// start profiling
|
||||||
|
status_t error = _kern_system_profiler_start(area, gOptions.interval,
|
||||||
|
gOptions.stack_depth);
|
||||||
|
if (error != B_OK) {
|
||||||
|
fprintf(stderr, "%s: Failed to start profiling: %s\n", kCommandName,
|
||||||
|
strerror(error));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// main event loop
|
||||||
|
while (true) {
|
||||||
|
// get the current buffer
|
||||||
|
size_t bufferStart = bufferHeader->start;
|
||||||
|
size_t bufferSize = bufferHeader->size;
|
||||||
|
uint8* buffer = bufferBase + bufferStart;
|
||||||
|
//printf("processing buffer of size %lu bytes\n", bufferSize);
|
||||||
|
|
||||||
|
if (bufferStart + bufferSize <= totalBufferSize) {
|
||||||
|
process_event_buffer(threadManager, buffer, bufferSize);
|
||||||
|
} else {
|
||||||
|
size_t remainingSize = bufferStart + bufferSize - totalBufferSize;
|
||||||
|
process_event_buffer(threadManager, buffer,
|
||||||
|
bufferSize - remainingSize);
|
||||||
|
process_event_buffer(threadManager, bufferBase, remainingSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get next buffer
|
||||||
|
error = _kern_system_profiler_next_buffer(bufferSize);
|
||||||
|
|
||||||
|
if (error != B_OK) {
|
||||||
|
if (error == B_INTERRUPTED) {
|
||||||
|
if (sCaughtDeadlySignal)
|
||||||
|
break;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "%s: Failed to get next sample buffer: %s\n",
|
||||||
|
kCommandName, strerror(error));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// stop profiling
|
||||||
|
_kern_system_profiler_stop();
|
||||||
|
|
||||||
|
// print results
|
||||||
|
int32 threadCount = threadManager.CountThreads();
|
||||||
|
for (int32 i = 0; i < threadCount; i++) {
|
||||||
|
Thread* thread = threadManager.ThreadAt(i);
|
||||||
|
thread->PrintResults();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, const char* const* argv)
|
main(int argc, const char* const* argv)
|
||||||
{
|
{
|
||||||
@ -239,17 +509,21 @@ main(int argc, const char* const* argv)
|
|||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
static struct option sLongOptions[] = {
|
static struct option sLongOptions[] = {
|
||||||
|
{ "all", no_argument, 0, 'a' },
|
||||||
{ "help", no_argument, 0, 'h' },
|
{ "help", no_argument, 0, 'h' },
|
||||||
{ 0, 0, 0, 0 }
|
{ 0, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
opterr = 0; // don't print errors
|
opterr = 0; // don't print errors
|
||||||
int c = getopt_long(argc, (char**)argv, "+cCfhi:klo:s:v:", sLongOptions,
|
int c = getopt_long(argc, (char**)argv, "+acCfhi:klo:s:v:",
|
||||||
NULL);
|
sLongOptions, NULL);
|
||||||
if (c == -1)
|
if (c == -1)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
case 'a':
|
||||||
|
gOptions.profile_all = true;
|
||||||
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
gOptions.profile_threads = false;
|
gOptions.profile_threads = false;
|
||||||
break;
|
break;
|
||||||
@ -289,15 +563,12 @@ main(int argc, const char* const* argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (optind >= argc)
|
if (!gOptions.profile_all && optind >= argc)
|
||||||
print_usage_and_exit(true);
|
print_usage_and_exit(true);
|
||||||
|
|
||||||
if (stackDepth != 0)
|
if (stackDepth != 0)
|
||||||
gOptions.stack_depth = stackDepth;
|
gOptions.stack_depth = stackDepth;
|
||||||
|
|
||||||
const char* const* programArgs = argv + optind;
|
|
||||||
int programArgCount = argc - optind;
|
|
||||||
|
|
||||||
if (outputFile != NULL) {
|
if (outputFile != NULL) {
|
||||||
gOptions.output = fopen(outputFile, "w+");
|
gOptions.output = fopen(outputFile, "w+");
|
||||||
if (gOptions.output == NULL) {
|
if (gOptions.output == NULL) {
|
||||||
@ -308,6 +579,14 @@ main(int argc, const char* const* argv)
|
|||||||
} else
|
} else
|
||||||
gOptions.output = stdout;
|
gOptions.output = stdout;
|
||||||
|
|
||||||
|
if (gOptions.profile_all) {
|
||||||
|
profile_all();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* const* programArgs = argv + optind;
|
||||||
|
int programArgCount = argc - optind;
|
||||||
|
|
||||||
// get thread/team to be debugged
|
// get thread/team to be debugged
|
||||||
thread_id threadID = -1;
|
thread_id threadID = -1;
|
||||||
team_id teamID = -1;
|
team_id teamID = -1;
|
||||||
@ -417,16 +696,14 @@ main(int argc, const char* const* argv)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case B_DEBUGGER_MESSAGE_IMAGE_CREATED:
|
case B_DEBUGGER_MESSAGE_IMAGE_CREATED:
|
||||||
if (Team* team = threadManager.FindTeam(message.origin.team)) {
|
threadManager.AddImage(message.origin.team,
|
||||||
team->AddImage(message.image_created.info,
|
message.image_created.info,
|
||||||
message.image_created.image_event);
|
message.image_created.image_event);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case B_DEBUGGER_MESSAGE_IMAGE_DELETED:
|
case B_DEBUGGER_MESSAGE_IMAGE_DELETED:
|
||||||
if (Team* team = threadManager.FindTeam(message.origin.team)) {
|
threadManager.RemoveImage(message.origin.team,
|
||||||
team->RemoveImage(message.image_deleted.info,
|
message.image_deleted.info.id,
|
||||||
message.image_deleted.image_event);
|
message.image_deleted.image_event);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case B_DEBUGGER_MESSAGE_POST_SYSCALL:
|
case B_DEBUGGER_MESSAGE_POST_SYSCALL:
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2005-2008, Ingo Weinhold, ingo_weinhold@gmx.de.
|
* Copyright 2005-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -18,8 +18,7 @@ using std::nothrow;
|
|||||||
|
|
||||||
|
|
||||||
struct debug_symbol_lookup_context {
|
struct debug_symbol_lookup_context {
|
||||||
debug_context context;
|
SymbolLookup* lookup;
|
||||||
SymbolLookup *lookup;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct debug_symbol_iterator : BPrivate::SymbolIterator {
|
struct debug_symbol_iterator : BPrivate::SymbolIterator {
|
||||||
@ -266,20 +265,19 @@ debug_get_stack_frame(debug_context *context, void *stackFrameAddress,
|
|||||||
|
|
||||||
// debug_create_symbol_lookup_context
|
// debug_create_symbol_lookup_context
|
||||||
status_t
|
status_t
|
||||||
debug_create_symbol_lookup_context(debug_context *debugContext,
|
debug_create_symbol_lookup_context(team_id team,
|
||||||
debug_symbol_lookup_context **_lookupContext)
|
debug_symbol_lookup_context **_lookupContext)
|
||||||
{
|
{
|
||||||
if (!debugContext || !_lookupContext)
|
if (team < 0 || !_lookupContext)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
// create the lookup context
|
// create the lookup context
|
||||||
debug_symbol_lookup_context *lookupContext
|
debug_symbol_lookup_context *lookupContext
|
||||||
= new(nothrow) debug_symbol_lookup_context;
|
= new(nothrow) debug_symbol_lookup_context;
|
||||||
lookupContext->context = *debugContext;
|
|
||||||
ObjectDeleter<debug_symbol_lookup_context> contextDeleter(lookupContext);
|
ObjectDeleter<debug_symbol_lookup_context> contextDeleter(lookupContext);
|
||||||
|
|
||||||
// create and init symbol lookup
|
// create and init symbol lookup
|
||||||
SymbolLookup *lookup = new(nothrow) SymbolLookup(debugContext->team);
|
SymbolLookup *lookup = new(nothrow) SymbolLookup(team);
|
||||||
if (!lookup)
|
if (!lookup)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2005-2006, Ingo Weinhold, bonefish@users.sf.net.
|
* Copyright 2005-2009, Ingo Weinhold, bonefish@users.sf.net.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -644,8 +644,7 @@ TeamDebugHandler::_PrintStackTrace(thread_id thread)
|
|||||||
if (error == B_OK) {
|
if (error == B_OK) {
|
||||||
// create a symbol lookup context
|
// create a symbol lookup context
|
||||||
debug_symbol_lookup_context *lookupContext = NULL;
|
debug_symbol_lookup_context *lookupContext = NULL;
|
||||||
error = debug_create_symbol_lookup_context(&fDebugContext,
|
error = debug_create_symbol_lookup_context(fTeam, &lookupContext);
|
||||||
&lookupContext);
|
|
||||||
if (error != B_OK) {
|
if (error != B_OK) {
|
||||||
debug_printf("debug_server: Failed to create symbol lookup "
|
debug_printf("debug_server: Failed to create symbol lookup "
|
||||||
"context: %s\n", strerror(error));
|
"context: %s\n", strerror(error));
|
||||||
|
Loading…
Reference in New Issue
Block a user