2009-04-18 17:38:21 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
|
|
|
* Distributed under the terms of the MIT License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <DebugEventStream.h>
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include <DataIO.h>
|
|
|
|
|
2009-04-19 11:17:24 +00:00
|
|
|
#include <system_profiler_defs.h>
|
|
|
|
|
2009-04-18 17:38:21 +00:00
|
|
|
|
|
|
|
#define INPUT_BUFFER_SIZE (128 * 1024)
|
|
|
|
|
|
|
|
|
|
|
|
BDebugEventInputStream::BDebugEventInputStream()
|
|
|
|
:
|
|
|
|
fStream(NULL),
|
|
|
|
fFlags(0),
|
|
|
|
fEventMask(0),
|
|
|
|
fBuffer(NULL),
|
|
|
|
fBufferCapacity(0),
|
|
|
|
fBufferSize(0),
|
2009-04-21 15:29:11 +00:00
|
|
|
fBufferPosition(0),
|
2009-04-30 12:24:25 +00:00
|
|
|
fStreamPosition(0),
|
2009-04-21 15:29:11 +00:00
|
|
|
fOwnsBuffer(false)
|
2009-04-18 17:38:21 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BDebugEventInputStream::~BDebugEventInputStream()
|
|
|
|
{
|
|
|
|
Unset();
|
|
|
|
|
2009-04-21 15:29:11 +00:00
|
|
|
if (fOwnsBuffer)
|
|
|
|
free(fBuffer);
|
2009-04-18 17:38:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
BDebugEventInputStream::SetTo(BDataIO* stream)
|
|
|
|
{
|
|
|
|
Unset();
|
|
|
|
|
|
|
|
// set the new values
|
|
|
|
if (stream == NULL)
|
|
|
|
return B_BAD_VALUE;
|
|
|
|
|
|
|
|
fStream = stream;
|
|
|
|
|
|
|
|
// allocate a buffer
|
|
|
|
if (fBuffer == NULL) {
|
|
|
|
fBuffer = (uint8*)malloc(INPUT_BUFFER_SIZE);
|
|
|
|
if (fBuffer == NULL) {
|
|
|
|
Unset();
|
|
|
|
return B_NO_MEMORY;
|
|
|
|
}
|
|
|
|
|
2009-04-21 15:29:11 +00:00
|
|
|
fOwnsBuffer = true;
|
2009-04-18 17:38:21 +00:00
|
|
|
fBufferCapacity = INPUT_BUFFER_SIZE;
|
|
|
|
fBufferSize = 0;
|
|
|
|
}
|
|
|
|
|
2009-04-21 15:29:11 +00:00
|
|
|
return _Init();
|
|
|
|
}
|
2009-04-18 17:38:21 +00:00
|
|
|
|
|
|
|
|
2009-04-21 15:29:11 +00:00
|
|
|
status_t
|
|
|
|
BDebugEventInputStream::SetTo(const void* data, size_t size,
|
|
|
|
bool takeOverOwnership)
|
|
|
|
{
|
|
|
|
Unset();
|
|
|
|
|
|
|
|
if (data == NULL || size == 0)
|
|
|
|
return B_BAD_VALUE;
|
|
|
|
|
|
|
|
if (fBuffer != NULL) {
|
|
|
|
if (fOwnsBuffer)
|
|
|
|
free(fBuffer);
|
|
|
|
fBuffer = NULL;
|
|
|
|
fBufferCapacity = 0;
|
|
|
|
fBufferSize = 0;
|
2009-04-18 17:38:21 +00:00
|
|
|
}
|
|
|
|
|
2009-04-21 15:29:11 +00:00
|
|
|
fBuffer = (uint8*)data;
|
|
|
|
fBufferCapacity = fBufferSize = size;
|
|
|
|
fOwnsBuffer = takeOverOwnership;
|
2009-04-18 17:38:21 +00:00
|
|
|
|
2009-04-21 15:29:11 +00:00
|
|
|
return _Init();
|
2009-04-18 17:38:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
BDebugEventInputStream::Unset()
|
|
|
|
{
|
|
|
|
fStream = NULL;
|
|
|
|
fFlags = 0;
|
|
|
|
fEventMask = 0;
|
2009-04-21 15:29:11 +00:00
|
|
|
|
|
|
|
// If we have a buffer that we own and has the right size, we keep it.
|
|
|
|
if (fOwnsBuffer) {
|
|
|
|
if (fBuffer != NULL && fBufferSize != INPUT_BUFFER_SIZE) {
|
|
|
|
free(fBuffer);
|
|
|
|
fBuffer = NULL;
|
|
|
|
fBufferCapacity = 0;
|
|
|
|
fBufferSize = 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
fBuffer = NULL;
|
|
|
|
fBufferCapacity = 0;
|
|
|
|
fBufferSize = 0;
|
|
|
|
}
|
2009-04-18 17:38:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-04-19 11:17:24 +00:00
|
|
|
/*! \brief Returns the next event in the stream.
|
|
|
|
|
|
|
|
At the end of the stream \c 0 is returned and \c *_buffer is set to \c NULL.
|
|
|
|
For events that don't have data associated with them, \c *_buffer will still
|
|
|
|
be non-NULL, even if dereferencing that address is not allowed.
|
|
|
|
|
|
|
|
\param _event Pointer to a pre-allocated location where the event ID shall
|
|
|
|
be stored.
|
|
|
|
\param _cpu Pointer to a pre-allocated location where the CPU index shall
|
|
|
|
be stored.
|
|
|
|
\param _buffer Pointer to a pre-allocated location where the pointer to the
|
|
|
|
event data shall be stored.
|
2009-04-30 12:24:25 +00:00
|
|
|
\param _streamOffset Pointer to a pre-allocated location where the event
|
|
|
|
header's offset relative to the beginning of the stream shall be stored.
|
|
|
|
May be \c NULL.
|
2009-04-19 11:17:24 +00:00
|
|
|
\return A negative error code in case an error occurred while trying to read
|
|
|
|
the info, the size of the data associated with the event otherwise.
|
|
|
|
*/
|
2009-04-18 17:38:21 +00:00
|
|
|
ssize_t
|
2009-04-19 11:17:24 +00:00
|
|
|
BDebugEventInputStream::ReadNextEvent(uint32* _event, uint32* _cpu,
|
2009-04-30 12:24:25 +00:00
|
|
|
const void** _buffer, off_t* _streamOffset)
|
2009-04-18 17:38:21 +00:00
|
|
|
{
|
|
|
|
// get the next header
|
|
|
|
status_t error = _GetData(sizeof(system_profiler_event_header));
|
|
|
|
if (error != B_OK) {
|
2009-04-19 11:17:24 +00:00
|
|
|
if (error == B_BAD_DATA && fBufferSize == 0) {
|
|
|
|
*_buffer = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
2009-04-18 17:38:21 +00:00
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2009-04-19 11:17:24 +00:00
|
|
|
system_profiler_event_header header
|
|
|
|
= *(system_profiler_event_header*)(fBuffer + fBufferPosition);
|
|
|
|
|
2009-04-30 12:24:25 +00:00
|
|
|
off_t streamOffset = fStreamPosition + fBufferPosition;
|
|
|
|
|
2009-04-19 11:17:24 +00:00
|
|
|
// skip the header in the buffer
|
|
|
|
fBufferSize -= sizeof(system_profiler_event_header);
|
|
|
|
fBufferPosition += sizeof(system_profiler_event_header);
|
2009-04-18 17:38:21 +00:00
|
|
|
|
|
|
|
// get the data
|
2009-04-19 11:17:24 +00:00
|
|
|
if (header.size > 0) {
|
|
|
|
error = _GetData(header.size);
|
2009-04-18 17:38:21 +00:00
|
|
|
if (error != B_OK)
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2009-04-19 11:17:24 +00:00
|
|
|
*_event = header.event;
|
|
|
|
*_cpu = header.cpu;
|
|
|
|
*_buffer = fBuffer + fBufferPosition;
|
2009-04-30 12:24:25 +00:00
|
|
|
if (_streamOffset)
|
|
|
|
*_streamOffset = streamOffset;
|
2009-04-18 17:38:21 +00:00
|
|
|
|
|
|
|
// skip the event in the buffer
|
2009-04-19 11:17:24 +00:00
|
|
|
fBufferSize -= header.size;
|
|
|
|
fBufferPosition += header.size;
|
2009-04-18 17:38:21 +00:00
|
|
|
|
2009-04-19 11:17:24 +00:00
|
|
|
return header.size;
|
2009-04-18 17:38:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-04-21 15:29:11 +00:00
|
|
|
status_t
|
|
|
|
BDebugEventInputStream::_Init()
|
|
|
|
{
|
2009-04-30 12:24:25 +00:00
|
|
|
fStreamPosition = 0;
|
2009-04-21 15:29:11 +00:00
|
|
|
fBufferPosition = 0;
|
|
|
|
|
|
|
|
// get the header
|
|
|
|
status_t error = _GetData(sizeof(debug_event_stream_header));
|
|
|
|
if (error != B_OK) {
|
|
|
|
Unset();
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
const debug_event_stream_header& header
|
|
|
|
= *(const debug_event_stream_header*)(fBuffer + fBufferPosition);
|
|
|
|
|
|
|
|
fBufferPosition += sizeof(debug_event_stream_header);
|
|
|
|
fBufferSize -= sizeof(debug_event_stream_header);
|
|
|
|
|
|
|
|
// check the header
|
|
|
|
if (strncmp(header.signature, B_DEBUG_EVENT_STREAM_SIGNATURE,
|
|
|
|
sizeof(header.signature)) != 0
|
|
|
|
|| header.version != B_DEBUG_EVENT_STREAM_VERSION
|
|
|
|
|| (header.flags & B_DEBUG_EVENT_STREAM_FLAG_HOST_ENDIAN) == 0) {
|
|
|
|
// TODO: Support non-host endianess!
|
|
|
|
Unset();
|
|
|
|
return B_BAD_DATA;
|
|
|
|
}
|
|
|
|
|
|
|
|
fFlags = header.flags;
|
|
|
|
fEventMask = header.event_mask;
|
|
|
|
|
|
|
|
return B_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-04-18 17:38:21 +00:00
|
|
|
ssize_t
|
|
|
|
BDebugEventInputStream::_Read(void* _buffer, size_t size)
|
|
|
|
{
|
|
|
|
uint8* buffer = (uint8*)_buffer;
|
|
|
|
size_t totalBytesRead = 0;
|
|
|
|
ssize_t bytesRead = 0;
|
|
|
|
|
|
|
|
while (size > 0 && (bytesRead = fStream->Read(buffer, size)) > 0) {
|
|
|
|
totalBytesRead += bytesRead;
|
|
|
|
buffer += bytesRead;
|
|
|
|
size -= bytesRead;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bytesRead < 0)
|
|
|
|
return bytesRead;
|
|
|
|
|
|
|
|
return totalBytesRead;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
BDebugEventInputStream::_GetData(size_t size)
|
|
|
|
{
|
|
|
|
if (fBufferSize >= size)
|
|
|
|
return B_OK;
|
|
|
|
|
|
|
|
if (size > fBufferCapacity)
|
|
|
|
return B_BUFFER_OVERFLOW;
|
|
|
|
|
|
|
|
// move remaining data to the start of the buffer
|
2009-04-19 23:44:20 +00:00
|
|
|
if (fBufferSize > 0 && fBufferPosition > 0)
|
2009-04-18 17:38:21 +00:00
|
|
|
memmove(fBuffer, fBuffer + fBufferPosition, fBufferSize);
|
2009-04-30 12:24:25 +00:00
|
|
|
fStreamPosition += fBufferPosition;
|
2009-04-19 23:44:20 +00:00
|
|
|
fBufferPosition = 0;
|
2009-04-18 17:38:21 +00:00
|
|
|
|
|
|
|
// read more data
|
2009-04-21 15:29:11 +00:00
|
|
|
if (fStream != NULL) {
|
|
|
|
ssize_t bytesRead = _Read(fBuffer + fBufferSize,
|
|
|
|
fBufferCapacity - fBufferSize);
|
|
|
|
if (bytesRead < 0)
|
|
|
|
return bytesRead;
|
|
|
|
|
|
|
|
fBufferSize += bytesRead;
|
|
|
|
}
|
2009-04-18 17:38:21 +00:00
|
|
|
|
|
|
|
return fBufferSize >= size ? B_OK : B_BAD_DATA;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// #pragma mark - BDebugEventOutputStream
|
|
|
|
|
|
|
|
|
|
|
|
BDebugEventOutputStream::BDebugEventOutputStream()
|
|
|
|
:
|
|
|
|
fStream(NULL),
|
|
|
|
fFlags(0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BDebugEventOutputStream::~BDebugEventOutputStream()
|
|
|
|
{
|
|
|
|
Unset();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
BDebugEventOutputStream::SetTo(BDataIO* stream, uint32 flags, uint32 eventMask)
|
|
|
|
{
|
|
|
|
Unset();
|
|
|
|
|
|
|
|
// set the new values
|
|
|
|
if (stream == NULL)
|
|
|
|
return B_BAD_VALUE;
|
|
|
|
|
|
|
|
fStream = stream;
|
|
|
|
fFlags = /*(flags & B_DEBUG_EVENT_STREAM_FLAG_ZIPPED)
|
|
|
|
|*/ B_DEBUG_EVENT_STREAM_FLAG_HOST_ENDIAN;
|
|
|
|
// TODO: Support zipped data!
|
|
|
|
|
|
|
|
// init and write the header
|
|
|
|
debug_event_stream_header header;
|
|
|
|
memset(header.signature, 0, sizeof(header.signature));
|
|
|
|
strlcpy(header.signature, B_DEBUG_EVENT_STREAM_SIGNATURE,
|
|
|
|
sizeof(header.signature));
|
|
|
|
header.version = B_DEBUG_EVENT_STREAM_VERSION;
|
|
|
|
header.flags = fFlags;
|
|
|
|
header.event_mask = eventMask;
|
|
|
|
|
|
|
|
ssize_t written = fStream->Write(&header, sizeof(header));
|
|
|
|
if (written < 0) {
|
|
|
|
Unset();
|
|
|
|
return written;
|
|
|
|
}
|
|
|
|
if ((size_t)written != sizeof(header)) {
|
|
|
|
Unset();
|
|
|
|
return B_FILE_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
return B_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
BDebugEventOutputStream::Unset()
|
|
|
|
{
|
|
|
|
Flush();
|
|
|
|
fStream = NULL;
|
|
|
|
fFlags = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
BDebugEventOutputStream::Write(const void* buffer, size_t size)
|
|
|
|
{
|
|
|
|
if (size == 0)
|
|
|
|
return B_OK;
|
|
|
|
if (buffer == NULL)
|
|
|
|
return B_BAD_VALUE;
|
|
|
|
|
|
|
|
ssize_t written = fStream->Write(buffer, size);
|
|
|
|
if (written < 0)
|
|
|
|
return written;
|
|
|
|
if ((size_t)written != size)
|
|
|
|
return B_FILE_ERROR;
|
|
|
|
|
|
|
|
return B_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
BDebugEventOutputStream::Flush()
|
|
|
|
{
|
|
|
|
return B_OK;
|
|
|
|
}
|