tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ExecutionTracerIntegration.cpp (6858B)


      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 "ExecutionTracerIntegration.h"
      8 
      9 #include "mozilla/dom/Attr.h"
     10 #include "mozilla/dom/BindingUtils.h"
     11 #include "mozilla/dom/Document.h"
     12 #include "mozilla/dom/DocumentFragment.h"
     13 #include "mozilla/dom/DOMException.h"
     14 #include "mozilla/dom/DOMExceptionBinding.h"
     15 #include "mozilla/dom/Element.h"
     16 #include "mozilla/dom/Location.h"
     17 #include "nsDOMAttributeMap.h"
     18 #include "nsQueryObject.h"
     19 
     20 #ifdef MOZ_EXECUTION_TRACING
     21 
     22 using namespace mozilla;
     23 using namespace mozilla::dom;
     24 
     25 template <prototypes::ID PrototypeID>
     26 bool DOMClassHasInterface(const DOMJSClass* aDomClass) {
     27  return aDomClass->mInterfaceChain[PrototypeTraits<PrototypeID>::Depth] ==
     28         PrototypeID;
     29 }
     30 
     31 bool ExecutionTracerIntegration::WriteNodeSummary(
     32    JSContext* aCx, nsINode* aNode, bool aNested,
     33    JS_TracerSummaryWriter* aWriter) {
     34  uint16_t nodeType = aNode->NodeType();
     35  const nsString& nodeName = aNode->NodeName();
     36  bool isConnected = aNode->IsInComposedDoc();
     37 
     38  aWriter->writeUint8(uint8_t(SummaryKind::Node));
     39  aWriter->writeUint16(nodeType);
     40  aWriter->writeTwoByteString(nodeName.get());
     41 
     42  if (RefPtr<Element> el = do_QueryObject(aNode)) {
     43    aWriter->writeUint8(uint8_t(isConnected) << 7 |
     44                        uint8_t(NodeSubkind::Element));
     45 
     46    nsDOMAttributeMap* attributes = el->Attributes();
     47    uint32_t attributesLength = attributes->Length();
     48 
     49    aWriter->writeUint32(attributesLength);
     50    for (uint32_t i = 0;
     51         i < attributesLength && i < JS::ValueSummary::MAX_COLLECTION_VALUES;
     52         ++i) {
     53      nsAutoString attrName;
     54      attributes->Item(i)->GetName(attrName);
     55      aWriter->writeTwoByteString(attrName.get());
     56 
     57      nsAutoString attrValue;
     58      attributes->Item(i)->GetValue(attrValue);
     59      aWriter->writeTwoByteString(attrValue.get());
     60    }
     61  } else if (RefPtr<Document> doc = do_QueryObject(aNode)) {
     62    aWriter->writeUint8(uint8_t(isConnected) << 7 |
     63                        uint8_t(NodeSubkind::Document));
     64    RefPtr<Location> location = doc->GetLocation();
     65    nsAutoCString href;
     66    if (location->GetHref(href) != NS_OK) {
     67      JS_ReportErrorASCII(aCx, "Failed to get document location's href");
     68      return false;
     69    }
     70    aWriter->writeUTF8String(href.get());
     71  } else if (Attr* attr = Attr::FromNode(aNode)) {
     72    aWriter->writeUint8(uint8_t(isConnected) << 7 | uint8_t(NodeSubkind::Attr));
     73    nsAutoString value;
     74    attr->GetValue(value);
     75    aWriter->writeTwoByteString(value.get());
     76  } else if (aNode->IsDocumentFragment()) {
     77    aWriter->writeUint8(uint8_t(isConnected) << 7 |
     78                        uint8_t(NodeSubkind::DocumentFragment));
     79 
     80    nsCOMPtr<nsINodeList> children = aNode->ChildNodes();
     81    if (!children) {
     82      JS_ReportErrorASCII(aCx, "OOM getting node's children");
     83      return false;
     84    }
     85 
     86    uint32_t numChildren = children->Length();
     87    aWriter->writeUint32(numChildren);
     88 
     89    if (!aNested) {
     90      for (uint32_t i = 0;
     91           i < numChildren && i < JS::ValueSummary::MAX_COLLECTION_VALUES;
     92           ++i) {
     93        nsCOMPtr<nsINode> child = children->Item(i);
     94        if (!child) {
     95          JS_ReportErrorASCII(aCx, "Failed getting child node");
     96          return false;
     97        }
     98 
     99        JS::Rooted<JS::Value> childValue(aCx);
    100        if (!ToJSValue(aCx, child.get(), &childValue)) {
    101          return false;
    102        }
    103 
    104        if (!aWriter->writeValue(aCx, childValue)) {
    105          return false;
    106        }
    107      }
    108    }
    109  } else if (aNode->IsText() || aNode->IsComment()) {
    110    if (aNode->IsText()) {
    111      aWriter->writeUint8(uint8_t(isConnected) << 7 |
    112                          uint8_t(NodeSubkind::Text));
    113    } else {
    114      aWriter->writeUint8(uint8_t(isConnected) << 7 |
    115                          uint8_t(NodeSubkind::Comment));
    116    }
    117    nsAutoString content;
    118    ErrorResult rv;
    119    aNode->GetTextContent(content, IgnoreErrors());
    120    aWriter->writeTwoByteString(content.get());
    121  } else {
    122    aWriter->writeUint8(uint8_t(isConnected) << 7 |
    123                        uint8_t(NodeSubkind::Other));
    124  }
    125 
    126  return true;
    127 }
    128 
    129 bool ExecutionTracerIntegration::WriteExceptionSummary(
    130    JSContext* aCx, JS::Handle<JSObject*> aObj, bool aNested,
    131    JS_TracerSummaryWriter* aWriter) {
    132  RefPtr<DOMException> domException;
    133  RefPtr<Exception> exception;
    134  UNWRAP_OBJECT(DOMException, aObj, domException);
    135  if (domException) {
    136    exception = domException;
    137  } else {
    138    // Not a DOM Exception, try XPC Exception.
    139    UNWRAP_OBJECT(Exception, aObj, exception);
    140    if (!exception) {
    141      return false;
    142    }
    143  }
    144  aWriter->writeUint8(uint8_t(SummaryKind::Exception));
    145 
    146  nsAutoString name;
    147  exception->GetName(name);
    148  aWriter->writeTwoByteString(name.get());
    149 
    150  nsAutoString message;
    151  exception->GetMessageMoz(message);
    152  aWriter->writeTwoByteString(message.get());
    153 
    154  if (domException) {
    155    uint16_t code = domException->Code();
    156    aWriter->writeUint16(code);
    157  } else {
    158    aWriter->writeUint16(0);
    159  }
    160 
    161  uint32_t result = exception->Result();
    162  aWriter->writeUint32(result);
    163 
    164  nsAutoCString fileName;
    165  exception->GetFilename(aCx, fileName);
    166  aWriter->writeUTF8String(fileName.get());
    167 
    168  uint32_t line = exception->LineNumber(aCx);
    169  aWriter->writeUint32(line);
    170 
    171  uint32_t column = exception->ColumnNumber(aCx);
    172  aWriter->writeUint32(column);
    173 
    174  nsCOMPtr<nsIStackFrame> stack = exception->GetLocation();
    175  nsAutoString stackString;
    176  if (stack) {
    177    stack->GetFormattedStack(aCx, stackString);
    178    aWriter->writeTwoByteString(stackString.get());
    179  } else {
    180    aWriter->writeTwoByteString(u"");
    181  }
    182 
    183  return true;
    184 }
    185 
    186 // static
    187 bool ExecutionTracerIntegration::Callback(JSContext* aCx,
    188                                          JS::Handle<JSObject*> aObj,
    189                                          bool aNested,
    190                                          JS_TracerSummaryWriter* aWriter) {
    191  aWriter->writeUint8(uint8_t(VERSION));
    192 
    193  const DOMJSClass* domClass = GetDOMClass(aObj);
    194  if (!domClass) {
    195    aWriter->writeUint8(uint8_t(SummaryKind::Other));
    196    return true;
    197  }
    198 
    199  if (DOMClassHasInterface<prototypes::id::Node>(domClass)) {
    200    nsINode* node = UnwrapDOMObject<nsINode>(aObj);
    201    if (!WriteNodeSummary(aCx, node, aNested, aWriter)) {
    202      return false;
    203    }
    204    return true;
    205  }
    206 
    207  if (DOMClassHasInterface<prototypes::id::DOMException>(domClass) ||
    208      DOMClassHasInterface<prototypes::id::Exception>(domClass)) {
    209    if (!WriteExceptionSummary(aCx, aObj, aNested, aWriter)) {
    210      return false;
    211    }
    212    return true;
    213  }
    214 
    215  aWriter->writeUint8(uint8_t(SummaryKind::Other));
    216  return true;
    217 }
    218 
    219 #endif