* Reorganized the image management. Introduced a SharedImage which knows the

symbols and is identified by name. Image does still represent a team-bound
  image, but it refers to a SharedImage for the symbols, now. This allows us
  to load the symbols for a shared object only once and share the data for all
  teams referring to it.
* Made the area used for system profiling writable. "-a -f" would segfault
  since the return addresses are sorted in-place.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30170 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2009-04-15 13:41:40 +00:00
parent 998210b432
commit afa231acb8
8 changed files with 155 additions and 273 deletions
@@ -14,8 +14,9 @@
struct HitSymbol { struct HitSymbol {
int64 hits; int64 hits;
Symbol* symbol; Symbol* symbol;
image_id imageID;
inline bool operator<(const HitSymbol& other) const inline bool operator<(const HitSymbol& other) const
{ {
@@ -146,6 +147,7 @@ BasicThreadProfileResult::PrintResults()
HitSymbol& hitSymbol = hitSymbols[hitSymbolCount++]; HitSymbol& hitSymbol = hitSymbols[hitSymbolCount++];
hitSymbol.hits = symbolHits[i]; hitSymbol.hits = symbolHits[i];
hitSymbol.symbol = symbols[i]; hitSymbol.symbol = symbols[i];
hitSymbol.imageID = image->ID();
} }
} }
} }
@@ -180,10 +182,9 @@ BasicThreadProfileResult::PrintResults()
"---------------------------------------\n"); "---------------------------------------\n");
for (int32 k = 0; k < imageCount; k++) { for (int32 k = 0; k < imageCount; k++) {
BasicThreadImage* image = images[k]; BasicThreadImage* image = images[k];
const image_info& imageInfo = image->GetImage()->Info();
fprintf(gOptions.output, " %10lld %10lld %7ld %s\n", fprintf(gOptions.output, " %10lld %10lld %7ld %s\n",
image->TotalHits(), image->UnknownHits(), imageInfo.id, image->TotalHits(), image->UnknownHits(),
imageInfo.name); image->GetImage()->ID(), image->GetImage()->Name());
} }
} }
@@ -198,7 +199,7 @@ BasicThreadProfileResult::PrintResults()
const Symbol* symbol = hitSymbol.symbol; const Symbol* symbol = hitSymbol.symbol;
fprintf(gOptions.output, " %10lld %10lld %6.2f %6ld %s\n", fprintf(gOptions.output, " %10lld %10lld %6.2f %6ld %s\n",
hitSymbol.hits, hitSymbol.hits * fInterval, hitSymbol.hits, hitSymbol.hits * fInterval,
100.0 * hitSymbol.hits / totalTicks, symbol->image->ID(), 100.0 * hitSymbol.hits / totalTicks, hitSymbol.imageID,
symbol->Name()); symbol->Name());
} }
} else } else
@@ -271,7 +271,7 @@ CallgrindThreadProfileResult::_PrintFunction(FILE* out,
int32 index = fNextImageOutputIndex++; int32 index = fNextImageOutputIndex++;
image->SetOutputIndex(index); image->SetOutputIndex(index);
fprintf(out, "%sob=(%ld) %s:%ld\n", called ? "c" : "", index, fprintf(out, "%sob=(%ld) %s:%ld\n", called ? "c" : "", index,
image->GetImage()->Info().name, image->ID()); image->GetImage()->Name(), image->ID());
} else { } else {
// image is already known // image is already known
// TODO: We may not need to print it at all! // TODO: We may not need to print it at all!
+7 -100
View File
@@ -5,115 +5,22 @@
#include "Image.h" #include "Image.h"
#include <stdio.h>
#include <algorithm> Image::Image(SharedImage* image, const image_info& info, team_id owner,
#include <new> int32 creationEvent)
#include <debug_support.h>
#include <ObjectList.h>
#include "Options.h"
Image::Image(const image_info& info, team_id owner, int32 creationEvent)
: :
fInfo(info), fImage(image),
fID(info.id),
fOwner(owner), fOwner(owner),
fSymbols(NULL), fLoadDelta((addr_t)info.text - (addr_t)image->Info().text),
fSymbolCount(0),
fCreationEvent(creationEvent), fCreationEvent(creationEvent),
fDeletionEvent(-1) fDeletionEvent(-1)
{ {
fImage->AddReference();
} }
Image::~Image() Image::~Image()
{ {
if (fSymbols != NULL) { fImage->RemoveReference();
for (int32 i = 0; i < fSymbolCount; i++)
delete fSymbols[i];
delete[] fSymbols;
}
}
status_t
Image::LoadSymbols(debug_symbol_lookup_context* lookupContext)
{
// fprintf(sOptions.output, "Loading symbols of image \"%s\" (%ld)...\n",
// fInfo.name, fInfo.id);
// create symbol iterator
debug_symbol_iterator* iterator;
status_t error = debug_create_image_symbol_iterator(lookupContext,
fInfo.id, &iterator);
if (error != B_OK) {
fprintf(stderr, "Failed to init symbol iterator: %s\n",
strerror(error));
return error;
}
// iterate through the symbols
BObjectList<Symbol> symbols(512, true);
char symbolName[1024];
int32 symbolType;
void* symbolLocation;
size_t symbolSize;
while (debug_next_image_symbol(iterator, symbolName, sizeof(symbolName),
&symbolType, &symbolLocation, &symbolSize) == B_OK) {
// printf(" %s %p (%6lu) %s\n",
// symbolType == B_SYMBOL_TYPE_TEXT ? "text" : "data",
// symbolLocation, symbolSize, symbolName);
if (symbolSize > 0 && symbolType == B_SYMBOL_TYPE_TEXT) {
Symbol* symbol = new(std::nothrow) Symbol(this,
(addr_t)symbolLocation, symbolSize, symbolName);
if (symbol == NULL || !symbols.AddItem(symbol)) {
delete symbol;
fprintf(stderr, "%s: Out of memory\n", kCommandName);
debug_delete_symbol_iterator(iterator);
return B_NO_MEMORY;
}
}
}
debug_delete_symbol_iterator(iterator);
// sort the symbols
fSymbolCount = symbols.CountItems();
fSymbols = new(std::nothrow) Symbol*[fSymbolCount];
if (fSymbols == NULL)
return B_NO_MEMORY;
for (int32 i = fSymbolCount - 1; i >= 0 ; i--)
fSymbols[i] = symbols.RemoveItemAt(i);
std::sort(fSymbols, fSymbols + fSymbolCount, SymbolComparator());
return B_OK;
}
int32
Image::FindSymbol(addr_t address) const
{
// binary search the function
int32 lower = 0;
int32 upper = fSymbolCount;
while (lower < upper) {
int32 mid = (lower + upper) / 2;
if (address >= fSymbols[mid]->base + fSymbols[mid]->size)
lower = mid + 1;
else
upper = mid;
}
if (lower == fSymbolCount)
return -1;
const Symbol* symbol = fSymbols[lower];
if (address >= symbol->base && address < symbol->base + symbol->size)
return lower;
return -1;
} }
+22 -54
View File
@@ -5,73 +5,35 @@
#ifndef IMAGE_H #ifndef IMAGE_H
#define IMAGE_H #define IMAGE_H
#include <image.h> #include "SharedImage.h"
#include <OS.h>
#include <String.h>
#include "Referenceable.h"
class debug_symbol_lookup_context;
class Image;
class Symbol {
public:
Symbol(Image* image, addr_t base, size_t size, const char* name)
:
image(image),
base(base),
size(size),
name(name)
{
}
const char* Name() const { return name.String(); }
Image* image;
addr_t base;
size_t size;
BString name;
};
struct SymbolComparator {
inline bool operator()(const Symbol* a, const Symbol* b) const
{
return a->base < b->base;
}
};
class Image : public Referenceable { class Image : public Referenceable {
public: public:
Image(const image_info& info, team_id owner, Image(SharedImage* image,
const image_info& info, team_id owner,
int32 creationEvent); int32 creationEvent);
~Image(); ~Image();
inline const image_id ID() const; inline const image_id ID() const;
inline const image_info& Info() const; inline const char* Name() const;
inline team_id Owner() const; inline team_id Owner() const;
inline int32 CreationEvent() const; inline int32 CreationEvent() const;
inline int32 DeletionEvent() const; inline int32 DeletionEvent() const;
inline void SetDeletionEvent(int32 event); inline void SetDeletionEvent(int32 event);
status_t LoadSymbols(
debug_symbol_lookup_context* lookupContext);
inline Symbol** Symbols() const; inline Symbol** Symbols() const;
inline int32 SymbolCount() const; inline int32 SymbolCount() const;
inline bool ContainsAddress(addr_t address) const; inline bool ContainsAddress(addr_t address) const;
int32 FindSymbol(addr_t address) const; inline int32 FindSymbol(addr_t address) const;
private: private:
image_info fInfo; SharedImage* fImage;
image_id fID;
team_id fOwner; team_id fOwner;
Symbol** fSymbols; addr_t fLoadDelta;
int32 fSymbolCount;
int32 fCreationEvent; int32 fCreationEvent;
int32 fDeletionEvent; int32 fDeletionEvent;
}; };
@@ -83,14 +45,14 @@ private:
const image_id const image_id
Image::ID() const Image::ID() const
{ {
return fInfo.id; return fID;
} }
const image_info& const char*
Image::Info() const Image::Name() const
{ {
return fInfo; return fImage->Name();
} }
@@ -125,22 +87,28 @@ Image::SetDeletionEvent(int32 event)
Symbol** Symbol**
Image::Symbols() const Image::Symbols() const
{ {
return fSymbols; return fImage->Symbols();
} }
int32 int32
Image::SymbolCount() const Image::SymbolCount() const
{ {
return fSymbolCount; return fImage->SymbolCount();
} }
bool bool
Image::ContainsAddress(addr_t address) const Image::ContainsAddress(addr_t address) const
{ {
return address >= (addr_t)fInfo.text return fImage->ContainsAddress(address - fLoadDelta);
&& address <= (addr_t)fInfo.data + fInfo.data_size - 1; }
int32
Image::FindSymbol(addr_t address) const
{
return fImage->FindSymbol(address - fLoadDelta);
} }
+1
View File
@@ -13,6 +13,7 @@ BinCommand profile
BasicThreadProfileResult.cpp BasicThreadProfileResult.cpp
CallgrindThreadProfileResult.cpp CallgrindThreadProfileResult.cpp
Image.cpp Image.cpp
SharedImage.cpp
Team.cpp Team.cpp
Thread.cpp Thread.cpp
profile.cpp profile.cpp
+15 -98
View File
@@ -78,37 +78,6 @@ Team::Init(team_id teamID, port_id debuggerPort)
return error; return error;
} }
// create symbol lookup context
debug_symbol_lookup_context* lookupContext;
error = debug_create_symbol_lookup_context(ID(), &lookupContext);
if (error != B_OK) {
fprintf(stderr, "%s: Failed to create symbol lookup context for "
"team %ld: %s\n", kCommandName, teamID, strerror(error));
return error;
}
// load the team's images and their symbols
error = _LoadSymbols(lookupContext, ID());
debug_delete_symbol_lookup_context(lookupContext);
if (error != B_OK)
return error;
// also try to load the kernel images and symbols
if (gOptions.profile_kernel) {
// create symbol lookup context
error = debug_create_symbol_lookup_context(B_SYSTEM_TEAM,
&lookupContext);
if (error != B_OK) {
fprintf(stderr, "%s: Failed to create symbol lookup context "
"for the kernel team: %s\n", kCommandName, strerror(error));
return error;
}
// load the kernel's images and their symbols
_LoadSymbols(lookupContext, B_SYSTEM_TEAM);
debug_delete_symbol_lookup_context(lookupContext);
}
// set team debugging flags // set team debugging flags
int32 teamDebugFlags = B_TEAM_DEBUG_THREADS int32 teamDebugFlags = B_TEAM_DEBUG_THREADS
| B_TEAM_DEBUG_TEAM_CREATION | B_TEAM_DEBUG_IMAGES; | B_TEAM_DEBUG_TEAM_CREATION | B_TEAM_DEBUG_IMAGES;
@@ -230,32 +199,28 @@ Team::Exec(int32 event)
status_t status_t
Team::AddImage(const image_info& imageInfo, team_id owner, int32 event) Team::AddImage(SharedImage* sharedImage, const image_info& imageInfo,
team_id owner, int32 event)
{ {
// create symbol lookup context // create the image
debug_symbol_lookup_context* lookupContext; Image* image = new(std::nothrow) Image(sharedImage, imageInfo, owner,
status_t error = debug_create_symbol_lookup_context(owner, &lookupContext); event);
if (error != B_OK) { if (image == NULL)
fprintf(stderr, "%s: Failed to create symbol lookup context for " return B_NO_MEMORY;
"team %ld: %s\n", kCommandName, owner, strerror(error));
return error;
}
Image* image; if (!fImages.AddItem(image)) {
error = _LoadImageSymbols(lookupContext, imageInfo, owner, event, delete image;
&image); return B_NO_MEMORY;
debug_delete_symbol_lookup_context(lookupContext); }
// Although we generally synchronize the threads' images lazily, we have // Although we generally synchronize the threads' images lazily, we have
// to add new images at least, since otherwise images could be added // to add new images at least, since otherwise images could be added
// and removed again, and the hits inbetween could never be matched. // and removed again, and the hits inbetween could never be matched.
if (error == B_OK) { ThreadList::Iterator it = fThreads.GetIterator();
ThreadList::Iterator it = fThreads.GetIterator(); while (Thread* thread = it.Next())
while (Thread* thread = it.Next()) thread->AddImage(image);
thread->AddImage(image);
}
return error; return B_OK;
} }
@@ -285,54 +250,6 @@ Team::FindImage(image_id id) const
} }
status_t
Team::_LoadSymbols(debug_symbol_lookup_context* lookupContext,
team_id owner)
{
// iterate through the team's images and collect the symbols
image_info imageInfo;
int32 cookie = 0;
while (get_next_image_info(owner, &cookie, &imageInfo) == B_OK) {
status_t error = _LoadImageSymbols(lookupContext, imageInfo,
owner, 0);
if (error == B_NO_MEMORY)
return error;
}
return B_OK;
}
status_t
Team::_LoadImageSymbols(debug_symbol_lookup_context* lookupContext,
const image_info& imageInfo, team_id owner, int32 event, Image** _image)
{
Image* image = new(std::nothrow) Image(imageInfo, owner, event);
if (image == NULL)
return B_NO_MEMORY;
status_t error = image->LoadSymbols(lookupContext);
if (error != B_OK) {
TRACE("Failed to load symbols of image %ld: %s\n", image->ID(),
strerror(error));
delete image;
return error;
}
TRACE("image %ld: loaded %ld symbols\n", image->ID(), image->SymbolCount());
if (!fImages.AddItem(image)) {
delete image;
return B_NO_MEMORY;
}
if (_image != NULL)
*_image = image;
return B_OK;
}
void void
Team::_RemoveImage(int32 index, int32 event) Team::_RemoveImage(int32 index, int32 event)
{ {
+3 -9
View File
@@ -28,8 +28,9 @@ public:
void Exec(int32 event); void Exec(int32 event);
status_t AddImage(const image_info& imageInfo, status_t AddImage(SharedImage* sharedImage,
team_id owner, int32 event); const image_info& imageInfo, team_id owner,
int32 event);
status_t RemoveImage(image_id imageID, int32 event); status_t RemoveImage(image_id imageID, int32 event);
inline const BObjectList<Image>& Images() const; inline const BObjectList<Image>& Images() const;
@@ -38,13 +39,6 @@ public:
inline team_id ID() const; inline team_id ID() const;
private: private:
status_t _LoadSymbols(
debug_symbol_lookup_context* lookupContext,
team_id owner);
status_t _LoadImageSymbols(
debug_symbol_lookup_context* lookupContext,
const image_info& imageInfo, team_id owner,
int32 event, Image** _image = NULL);
void _RemoveImage(int32 index, int32 event); void _RemoveImage(int32 index, int32 event);
bool _SynchronousProfiling() const bool _SynchronousProfiling() const
+99 -5
View File
@@ -11,7 +11,9 @@
#include <string.h> #include <string.h>
#include <algorithm> #include <algorithm>
#include <map>
#include <new> #include <new>
#include <string>
#include <debugger.h> #include <debugger.h>
#include <OS.h> #include <OS.h>
@@ -20,6 +22,7 @@
#include <syscalls.h> #include <syscalls.h>
#include <system_profiler_defs.h> #include <system_profiler_defs.h>
#include <AutoDeleter.h>
#include <debug_support.h> #include <debug_support.h>
#include <ObjectList.h> #include <ObjectList.h>
#include <Referenceable.h> #include <Referenceable.h>
@@ -98,6 +101,13 @@ public:
{ {
} }
~ThreadManager()
{
// release image references
for (ImageMap::iterator it = fImages.begin(); it != fImages.end(); ++it)
it->second->RemoveReference();
}
status_t AddTeam(team_id teamID, Team** _team = NULL) status_t AddTeam(team_id teamID, Team** _team = NULL)
{ {
return _AddTeam(teamID, NULL, _team); return _AddTeam(teamID, NULL, _team);
@@ -186,16 +196,24 @@ public:
status_t AddImage(team_id teamID, const image_info& imageInfo, int32 event) status_t AddImage(team_id teamID, const image_info& imageInfo, int32 event)
{ {
// get a shared image
SharedImage* sharedImage;
status_t error = _GetSharedImage(teamID, imageInfo, &sharedImage);
if (error != B_OK)
return error;
if (teamID == B_SYSTEM_TEAM) { if (teamID == B_SYSTEM_TEAM) {
// a kernel image -- add it to all teams // a kernel image -- add it to all teams
int32 count = fTeams.CountItems(); int32 count = fTeams.CountItems();
for (int32 i = 0; i < count; i++) for (int32 i = 0; i < count; i++) {
fTeams.ItemAt(i)->AddImage(imageInfo, teamID, event); fTeams.ItemAt(i)->AddImage(sharedImage, imageInfo, teamID,
event);
}
} }
// a userland team image -- add it to that image // a userland team image -- add it to that image
if (Team* team = FindTeam(teamID)) if (Team* team = FindTeam(teamID))
return team->AddImage(imageInfo, teamID, event); return team->AddImage(sharedImage, imageInfo, teamID, event);
return B_BAD_TEAM_ID; return B_BAD_TEAM_ID;
} }
@@ -227,7 +245,7 @@ private:
status_t error = addedInfo != NULL status_t error = addedInfo != NULL
? team->Init(addedInfo) ? team->Init(addedInfo)
: team->Init(teamID, fDebuggerPort); : _InitDebuggedTeam(team, teamID);
if (error != B_OK) { if (error != B_OK) {
delete team; delete team;
return error; return error;
@@ -241,6 +259,43 @@ private:
return B_OK; return B_OK;
} }
status_t _InitDebuggedTeam(Team* team, team_id teamID)
{
// init the team
status_t error = team->Init(teamID, fDebuggerPort);
if (error != B_OK)
return error;
// add the team's images
error = _LoadTeamImages(team, teamID);
if (error != B_OK)
return error;
// add the kernel images
return _LoadTeamImages(team, B_SYSTEM_TEAM);
}
status_t _LoadTeamImages(Team* team, team_id teamID)
{
// iterate through the team's images and collect the symbols
image_info imageInfo;
int32 cookie = 0;
while (get_next_image_info(teamID, &cookie, &imageInfo) == B_OK) {
// get a shared image
SharedImage* sharedImage;
status_t error = _GetSharedImage(teamID, imageInfo, &sharedImage);
if (error != B_OK)
return error;
// add the image to the team
error = team->AddImage(sharedImage, imageInfo, teamID, 0);
if (error != B_OK)
return error;
}
return B_OK;
}
status_t _CreateThreadProfileResult(Thread* thread) status_t _CreateThreadProfileResult(Thread* thread)
{ {
ThreadProfileResult* profileResult; ThreadProfileResult* profileResult;
@@ -264,9 +319,47 @@ private:
return B_OK; return B_OK;
} }
status_t _GetSharedImage(team_id teamID, const image_info& imageInfo,
SharedImage** _sharedImage)
{
// check whether the image has already been loaded
ImageMap::iterator it = fImages.find(imageInfo.name);
if (it != fImages.end()) {
*_sharedImage = it->second;
return B_OK;
}
// create the shared image
SharedImage* sharedImage = new(std::nothrow) SharedImage;
if (sharedImage == NULL)
return B_NO_MEMORY;
ObjectDeleter<SharedImage> imageDeleter(sharedImage);
// load the symbols
status_t error = teamID == B_SYSTEM_TEAM
? sharedImage->Init(teamID, imageInfo.id)
: sharedImage->Init(imageInfo.name);
if (error != B_OK)
return error;
try {
fImages[sharedImage->Name()] = sharedImage;
} catch (std::bad_alloc) {
return B_NO_MEMORY;
}
imageDeleter.Detach();
*_sharedImage = sharedImage;
return B_OK;
}
private:
typedef std::map<string, SharedImage*> ImageMap;
private: private:
BObjectList<Team> fTeams; BObjectList<Team> fTeams;
BObjectList<Thread> fThreads; BObjectList<Thread> fThreads;
ImageMap fImages;
port_id fDebuggerPort; port_id fDebuggerPort;
}; };
@@ -433,7 +526,8 @@ profile_all()
// create and area for the sample buffer // create and area for the sample buffer
system_profiler_buffer_header* bufferHeader; system_profiler_buffer_header* bufferHeader;
area_id area = create_area("profiling buffer", (void**)&bufferHeader, area_id area = create_area("profiling buffer", (void**)&bufferHeader,
B_ANY_ADDRESS, PROFILE_ALL_SAMPLE_AREA_SIZE, B_NO_LOCK, B_READ_AREA); B_ANY_ADDRESS, PROFILE_ALL_SAMPLE_AREA_SIZE, B_NO_LOCK,
B_READ_AREA | B_WRITE_AREA);
if (area < 0) { if (area < 0) {
fprintf(stderr, "%s: Failed to create sample area: %s\n", kCommandName, fprintf(stderr, "%s: Failed to create sample area: %s\n", kCommandName,
strerror(area)); strerror(area));