LCOV - code coverage report
Current view: top level - ipc/glue - CrashReporterMetadataShmem.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 4 103 3.9 %
Date: 2017-07-14 16:53:18 Functions: 1 20 5.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "CrashReporterMetadataShmem.h"
       8             : #include "mozilla/Attributes.h"
       9             : #include "nsISupportsImpl.h"
      10             : 
      11             : namespace mozilla {
      12             : namespace ipc {
      13             : 
      14             : enum class EntryType : uint8_t {
      15             :   None,
      16             :   Annotation,
      17             : };
      18             : 
      19           2 : CrashReporterMetadataShmem::CrashReporterMetadataShmem(const Shmem& aShmem)
      20           2 :  : mShmem(aShmem)
      21             : {
      22           2 :   MOZ_COUNT_CTOR(CrashReporterMetadataShmem);
      23           2 : }
      24             : 
      25           0 : CrashReporterMetadataShmem::~CrashReporterMetadataShmem()
      26             : {
      27           0 :   MOZ_COUNT_DTOR(CrashReporterMetadataShmem);
      28           0 : }
      29             : 
      30             : void
      31           0 : CrashReporterMetadataShmem::AnnotateCrashReport(const nsCString& aKey, const nsCString& aData)
      32             : {
      33           0 :   mNotes.Put(aKey, aData);
      34           0 :   SyncNotesToShmem();
      35           0 : }
      36             : 
      37             : void
      38           0 : CrashReporterMetadataShmem::AppendAppNotes(const nsCString& aData)
      39             : {
      40           0 :   mAppNotes.Append(aData);
      41           0 :   mNotes.Put(NS_LITERAL_CSTRING("Notes"), mAppNotes);
      42           0 :   SyncNotesToShmem();
      43           0 : }
      44             : 
      45             : class MOZ_STACK_CLASS MetadataShmemWriter
      46             : {
      47             : public:
      48           0 :   explicit MetadataShmemWriter(const Shmem& aShmem)
      49           0 :    : mCursor(aShmem.get<uint8_t>()),
      50           0 :      mEnd(mCursor + aShmem.Size<uint8_t>())
      51             :   {
      52           0 :     *mCursor = uint8_t(EntryType::None);
      53           0 :   }
      54             : 
      55           0 :   MOZ_MUST_USE bool WriteAnnotation(const nsCString& aKey, const nsCString& aValue) {
      56             :     // This shouldn't happen because Commit() guarantees mCursor < mEnd. But
      57             :     // we might as well be safe.
      58           0 :     if (mCursor >= mEnd) {
      59           0 :       return false;
      60             :     }
      61             : 
      62             :     // Save the current position so we can write the entry type if the entire
      63             :     // entry fits.
      64           0 :     uint8_t* start = mCursor++;
      65           0 :     if (!Write(aKey) || !Write(aValue)) {
      66           0 :       return false;
      67             :     }
      68           0 :     return Commit(start, EntryType::Annotation);
      69             :   }
      70             : 
      71             : private:
      72             :   // On success, append a new terminal byte. On failure, rollback the cursor.
      73           0 :   MOZ_MUST_USE bool Commit(uint8_t* aStart, EntryType aType) {
      74           0 :     MOZ_ASSERT(aStart < mEnd);
      75           0 :     MOZ_ASSERT(EntryType(*aStart) == EntryType::None);
      76             : 
      77           0 :     if (mCursor >= mEnd) {
      78             :       // No room for a terminating byte - rollback.
      79           0 :       mCursor = aStart;
      80           0 :       return false;
      81             :     }
      82             : 
      83             :     // Commit the entry and write a new terminal byte.
      84           0 :     *aStart = uint8_t(aType);
      85           0 :     *mCursor = uint8_t(EntryType::None);
      86           0 :     return true;
      87             :   }
      88             : 
      89           0 :   MOZ_MUST_USE bool Write(const nsCString& aString) {
      90             :     // 32-bit length is okay since our shmems are very small (16K),
      91             :     // a huge write would fail anyway.
      92           0 :     return Write(static_cast<uint32_t>(aString.Length())) &&
      93           0 :            Write(aString.get(), aString.Length());
      94             :   }
      95             : 
      96             :   template <typename T>
      97           0 :   MOZ_MUST_USE bool Write(const T& aT) {
      98           0 :     return Write(&aT, sizeof(T));
      99             :   }
     100             : 
     101           0 :   MOZ_MUST_USE bool Write(const void* aData, size_t aLength) {
     102           0 :     if (size_t(mEnd - mCursor) < aLength) {
     103           0 :       return false;
     104             :     }
     105           0 :     memcpy(mCursor, aData, aLength);
     106           0 :     mCursor += aLength;
     107           0 :     return true;
     108             :   }
     109             : 
     110             :  private:
     111             :   // The cursor (beginning at start) always points to a single byte
     112             :   // representing the next EntryType. An EntryType is either None,
     113             :   // indicating there are no more entries, or Annotation, meaning
     114             :   // two strings follow.
     115             :   //
     116             :   // Strings are written as a 32-bit length and byte sequence. After each new
     117             :   // entry, a None entry is always appended, and a subsequent entry will
     118             :   // overwrite this byte.
     119             :   uint8_t* mCursor;
     120             :   uint8_t* mEnd;
     121             : };
     122             : 
     123             : void
     124           0 : CrashReporterMetadataShmem::SyncNotesToShmem()
     125             : {
     126           0 :   MetadataShmemWriter writer(mShmem);
     127             : 
     128           0 :   for (auto it = mNotes.Iter(); !it.Done(); it.Next()) {
     129           0 :     nsCString key = nsCString(it.Key());
     130           0 :     nsCString value = nsCString(it.Data());
     131           0 :     if (!writer.WriteAnnotation(key, value)) {
     132           0 :       return;
     133             :     }
     134             :   }
     135             : }
     136             : 
     137             : // Helper class to iterate over metadata entries encoded in shmem.
     138             : class MOZ_STACK_CLASS MetadataShmemReader
     139             : {
     140             : public:
     141           0 :   explicit MetadataShmemReader(const Shmem& aShmem)
     142           0 :    : mEntryType(EntryType::None)
     143             :   {
     144           0 :     mCursor = aShmem.get<uint8_t>();
     145           0 :     mEnd = mCursor + aShmem.Size<uint8_t>();
     146             : 
     147             :     // Advance to the first item, if any.
     148           0 :     Next();
     149           0 :   }
     150             : 
     151           0 :   bool Done() const {
     152           0 :     return mCursor >= mEnd || Type() == EntryType::None;
     153             :   }
     154           0 :   EntryType Type() const {
     155           0 :     return mEntryType;
     156             :   }
     157           0 :   void Next() {
     158           0 :     if (mCursor < mEnd) {
     159           0 :       mEntryType = EntryType(*mCursor++);
     160             :     } else {
     161           0 :       mEntryType = EntryType::None;
     162             :     }
     163           0 :   }
     164             : 
     165           0 :   bool Read(nsCString& aOut) {
     166           0 :     uint32_t length = 0;
     167           0 :     if (!Read(&length)) {
     168           0 :       return false;
     169             :     }
     170             : 
     171           0 :     const uint8_t* src = Read(length);
     172           0 :     if (!src) {
     173           0 :       return false;
     174             :     }
     175             : 
     176           0 :     aOut.Assign((const char *)src, length);
     177           0 :     return true;
     178             :   }
     179             : 
     180             : private:
     181             :   template <typename T>
     182           0 :   bool Read(T* aOut) {
     183           0 :     return Read(aOut, sizeof(T));
     184             :   }
     185           0 :   bool Read(void* aOut, size_t aLength) {
     186           0 :     const uint8_t* src = Read(aLength);
     187           0 :     if (!src) {
     188           0 :       return false;
     189             :     }
     190           0 :     memcpy(aOut, src, aLength);
     191           0 :     return true;
     192             :   }
     193             : 
     194             :   // If buffer has |aLength| bytes, return cursor and then advance it.
     195             :   // Otherwise, return null.
     196           0 :   const uint8_t* Read(size_t aLength) {
     197           0 :     if (size_t(mEnd - mCursor) < aLength) {
     198           0 :       return nullptr;
     199             :     }
     200           0 :     const uint8_t* result = mCursor;
     201           0 :     mCursor += aLength;
     202           0 :     return result;
     203             :   }
     204             : 
     205             : private:
     206             :   const uint8_t* mCursor;
     207             :   const uint8_t* mEnd;
     208             :   EntryType mEntryType;
     209             : };
     210             : 
     211             : #ifdef MOZ_CRASHREPORTER
     212             : void
     213           0 : CrashReporterMetadataShmem::ReadAppNotes(const Shmem& aShmem, CrashReporter::AnnotationTable* aNotes)
     214             : {
     215           0 :   for (MetadataShmemReader reader(aShmem); !reader.Done(); reader.Next()) {
     216           0 :     switch (reader.Type()) {
     217             :       case EntryType::Annotation: {
     218           0 :         nsCString key, value;
     219           0 :         if (!reader.Read(key) || !reader.Read(value)) {
     220           0 :           return;
     221             :         }
     222             : 
     223           0 :         aNotes->Put(key, value);
     224           0 :         break;
     225             :       }
     226             :       default:
     227           0 :         NS_ASSERTION(false, "Unknown metadata entry type");
     228           0 :         break;
     229             :     }
     230             :   }
     231             : }
     232             : #endif
     233             : 
     234             : } // namespace ipc
     235             : } // namespace mozilla

Generated by: LCOV version 1.13