1 /* 2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include <DebugEventStream.h> 7 8 #include <stdlib.h> 9 #include <string.h> 10 11 #include <DataIO.h> 12 13 #include <system_profiler_defs.h> 14 15 16 #define INPUT_BUFFER_SIZE (128 * 1024) 17 18 19 BDebugEventInputStream::BDebugEventInputStream() 20 : 21 fStream(NULL), 22 fFlags(0), 23 fEventMask(0), 24 fBuffer(NULL), 25 fBufferCapacity(0), 26 fBufferSize(0), 27 fBufferPosition(0), 28 fStreamPosition(0), 29 fOwnsBuffer(false) 30 { 31 } 32 33 34 BDebugEventInputStream::~BDebugEventInputStream() 35 { 36 Unset(); 37 38 if (fOwnsBuffer) 39 free(fBuffer); 40 } 41 42 43 status_t 44 BDebugEventInputStream::SetTo(BDataIO* stream) 45 { 46 Unset(); 47 48 // set the new values 49 if (stream == NULL) 50 return B_BAD_VALUE; 51 52 fStream = stream; 53 54 // allocate a buffer 55 if (fBuffer == NULL) { 56 fBuffer = (uint8*)malloc(INPUT_BUFFER_SIZE); 57 if (fBuffer == NULL) { 58 Unset(); 59 return B_NO_MEMORY; 60 } 61 62 fOwnsBuffer = true; 63 fBufferCapacity = INPUT_BUFFER_SIZE; 64 fBufferSize = 0; 65 } 66 67 return _Init(); 68 } 69 70 71 status_t 72 BDebugEventInputStream::SetTo(const void* data, size_t size, 73 bool takeOverOwnership) 74 { 75 Unset(); 76 77 if (data == NULL || size == 0) 78 return B_BAD_VALUE; 79 80 if (fBuffer != NULL) { 81 if (fOwnsBuffer) 82 free(fBuffer); 83 fBuffer = NULL; 84 fBufferCapacity = 0; 85 fBufferSize = 0; 86 } 87 88 fBuffer = (uint8*)data; 89 fBufferCapacity = fBufferSize = size; 90 fOwnsBuffer = takeOverOwnership; 91 92 return _Init(); 93 } 94 95 96 void 97 BDebugEventInputStream::Unset() 98 { 99 fStream = NULL; 100 fFlags = 0; 101 fEventMask = 0; 102 103 // If we have a buffer that we own and has the right size, we keep it. 104 if (fOwnsBuffer) { 105 if (fBuffer != NULL && fBufferSize != INPUT_BUFFER_SIZE) { 106 free(fBuffer); 107 fBuffer = NULL; 108 fBufferCapacity = 0; 109 fBufferSize = 0; 110 } 111 } else { 112 fBuffer = NULL; 113 fBufferCapacity = 0; 114 fBufferSize = 0; 115 } 116 } 117 118 119 /*! \brief Returns the next event in the stream. 120 121 At the end of the stream \c 0 is returned and \c *_buffer is set to \c NULL. 122 For events that don't have data associated with them, \c *_buffer will still 123 be non-NULL, even if dereferencing that address is not allowed. 124 125 \param _event Pointer to a pre-allocated location where the event ID shall 126 be stored. 127 \param _cpu Pointer to a pre-allocated location where the CPU index shall 128 be stored. 129 \param _buffer Pointer to a pre-allocated location where the pointer to the 130 event data shall be stored. 131 \param _streamOffset Pointer to a pre-allocated location where the event 132 header's offset relative to the beginning of the stream shall be stored. 133 May be \c NULL. 134 \return A negative error code in case an error occurred while trying to read 135 the info, the size of the data associated with the event otherwise. 136 */ 137 ssize_t 138 BDebugEventInputStream::ReadNextEvent(uint32* _event, uint32* _cpu, 139 const void** _buffer, off_t* _streamOffset) 140 { 141 // get the next header 142 status_t error = _GetData(sizeof(system_profiler_event_header)); 143 if (error != B_OK) { 144 if (error == B_BAD_DATA && fBufferSize == 0) { 145 *_buffer = NULL; 146 return 0; 147 } 148 return error; 149 } 150 151 system_profiler_event_header header 152 = *(system_profiler_event_header*)(fBuffer + fBufferPosition); 153 154 off_t streamOffset = fStreamPosition + fBufferPosition; 155 156 // skip the header in the buffer 157 fBufferSize -= sizeof(system_profiler_event_header); 158 fBufferPosition += sizeof(system_profiler_event_header); 159 160 // get the data 161 if (header.size > 0) { 162 error = _GetData(header.size); 163 if (error != B_OK) 164 return error; 165 } 166 167 *_event = header.event; 168 *_cpu = header.cpu; 169 *_buffer = fBuffer + fBufferPosition; 170 if (_streamOffset) 171 *_streamOffset = streamOffset; 172 173 // skip the event in the buffer 174 fBufferSize -= header.size; 175 fBufferPosition += header.size; 176 177 return header.size; 178 } 179 180 181 status_t 182 BDebugEventInputStream::_Init() 183 { 184 fStreamPosition = 0; 185 fBufferPosition = 0; 186 187 // get the header 188 status_t error = _GetData(sizeof(debug_event_stream_header)); 189 if (error != B_OK) { 190 Unset(); 191 return error; 192 } 193 const debug_event_stream_header& header 194 = *(const debug_event_stream_header*)(fBuffer + fBufferPosition); 195 196 fBufferPosition += sizeof(debug_event_stream_header); 197 fBufferSize -= sizeof(debug_event_stream_header); 198 199 // check the header 200 if (strncmp(header.signature, B_DEBUG_EVENT_STREAM_SIGNATURE, 201 sizeof(header.signature)) != 0 202 || header.version != B_DEBUG_EVENT_STREAM_VERSION 203 || (header.flags & B_DEBUG_EVENT_STREAM_FLAG_HOST_ENDIAN) == 0) { 204 // TODO: Support non-host endianess! 205 Unset(); 206 return B_BAD_DATA; 207 } 208 209 fFlags = header.flags; 210 fEventMask = header.event_mask; 211 212 return B_OK; 213 } 214 215 216 ssize_t 217 BDebugEventInputStream::_Read(void* _buffer, size_t size) 218 { 219 uint8* buffer = (uint8*)_buffer; 220 size_t totalBytesRead = 0; 221 ssize_t bytesRead = 0; 222 223 while (size > 0 && (bytesRead = fStream->Read(buffer, size)) > 0) { 224 totalBytesRead += bytesRead; 225 buffer += bytesRead; 226 size -= bytesRead; 227 } 228 229 if (bytesRead < 0) 230 return bytesRead; 231 232 return totalBytesRead; 233 } 234 235 236 status_t 237 BDebugEventInputStream::_GetData(size_t size) 238 { 239 if (fBufferSize >= size) 240 return B_OK; 241 242 if (size > fBufferCapacity) 243 return B_BUFFER_OVERFLOW; 244 245 // move remaining data to the start of the buffer 246 if (fBufferSize > 0 && fBufferPosition > 0) 247 memmove(fBuffer, fBuffer + fBufferPosition, fBufferSize); 248 fStreamPosition += fBufferPosition; 249 fBufferPosition = 0; 250 251 // read more data 252 if (fStream != NULL) { 253 ssize_t bytesRead = _Read(fBuffer + fBufferSize, 254 fBufferCapacity - fBufferSize); 255 if (bytesRead < 0) 256 return bytesRead; 257 258 fBufferSize += bytesRead; 259 } 260 261 return fBufferSize >= size ? B_OK : B_BAD_DATA; 262 } 263 264 265 // #pragma mark - BDebugEventOutputStream 266 267 268 BDebugEventOutputStream::BDebugEventOutputStream() 269 : 270 fStream(NULL), 271 fFlags(0) 272 { 273 } 274 275 276 BDebugEventOutputStream::~BDebugEventOutputStream() 277 { 278 Unset(); 279 } 280 281 282 status_t 283 BDebugEventOutputStream::SetTo(BDataIO* stream, uint32 flags, uint32 eventMask) 284 { 285 Unset(); 286 287 // set the new values 288 if (stream == NULL) 289 return B_BAD_VALUE; 290 291 fStream = stream; 292 fFlags = /*(flags & B_DEBUG_EVENT_STREAM_FLAG_ZIPPED) 293 |*/ B_DEBUG_EVENT_STREAM_FLAG_HOST_ENDIAN; 294 // TODO: Support zipped data! 295 296 // init and write the header 297 debug_event_stream_header header; 298 memset(header.signature, 0, sizeof(header.signature)); 299 strlcpy(header.signature, B_DEBUG_EVENT_STREAM_SIGNATURE, 300 sizeof(header.signature)); 301 header.version = B_DEBUG_EVENT_STREAM_VERSION; 302 header.flags = fFlags; 303 header.event_mask = eventMask; 304 305 ssize_t written = fStream->Write(&header, sizeof(header)); 306 if (written < 0) { 307 Unset(); 308 return written; 309 } 310 if ((size_t)written != sizeof(header)) { 311 Unset(); 312 return B_FILE_ERROR; 313 } 314 315 return B_OK; 316 } 317 318 319 void 320 BDebugEventOutputStream::Unset() 321 { 322 Flush(); 323 fStream = NULL; 324 fFlags = 0; 325 } 326 327 328 status_t 329 BDebugEventOutputStream::Write(const void* buffer, size_t size) 330 { 331 if (size == 0) 332 return B_OK; 333 if (buffer == NULL) 334 return B_BAD_VALUE; 335 336 ssize_t written = fStream->Write(buffer, size); 337 if (written < 0) 338 return written; 339 if ((size_t)written != size) 340 return B_FILE_ERROR; 341 342 return B_OK; 343 } 344 345 346 status_t 347 BDebugEventOutputStream::Flush() 348 { 349 return B_OK; 350 } 351