Example #1
0
	static void AppendAsChildren( const spINode & contextNode, const spINode & parsedNode ) {
		if ( !contextNode )
			NOTIFY_ERROR( IError::kEDParser, kPECInvalidContextNode, "Context Node is invalid", IError::kESOperationFatal, false, false );
		auto contextNodeType = contextNode->GetNodeType();
		if ( contextNodeType != INode::kNTStructure && contextNodeType != INode::kNTArray )
			NOTIFY_ERROR( IError::kEDParser, kPECContextNodeIsNonComposite, "Context Node is non composite", IError::kESOperationFatal,
				true, static_cast< sizet >( contextNodeType ) );
		pICompositeNode compositeContextNode = contextNode->GetInterfacePointer< ICompositeNode >();
		pIMetadata meta( NULL );
		try {
			meta = parsedNode->GetInterfacePointer< IMetadata >();
		} catch ( spcIError err ) {
			meta = NULL;
		}
		if ( meta ) {
			auto it = meta->Iterator();
			while ( it ) {
				auto childNode = it->GetNode();
				it = it->Next();
				childNode = meta->GetIMetadata_I()->RemoveNode( childNode->GetNameSpace(), childNode->GetName() );
				compositeContextNode->AppendNode( childNode );
			}
		} else {
			compositeContextNode->AppendNode( parsedNode );
		}
	}
Example #2
0
	static void InsertAfter( const spINode & contextNode, const spINode & parsedNode ) {
		if ( !contextNode )
			NOTIFY_ERROR( IError::kEDParser, kPECInvalidContextNode, "Context Node is invalid", IError::kESOperationFatal, false, false );
		if ( !contextNode->IsArrayItem() )
			NOTIFY_ERROR( IError::kEDParser, kPECContextNodeParentIsNonArray, "Context Node's Parent is non array node", IError::kESOperationFatal, false, false );
		pIMetadata meta( NULL );
		try {
			meta = parsedNode->GetInterfacePointer< IMetadata >();
		} catch ( spcIError err ) {
			meta = NULL;
		}
		pIArrayNode parentArrayNode = contextNode->GetINode_I()->GetRawParentPointer()->GetInterfacePointer< IArrayNode >();
		if ( meta ) {
			auto it = meta->Iterator();
			sizet index = contextNode->GetIndex() + 1;
			while ( it ) {
				auto childNode = it->GetNode();
				it = it->Next();
				childNode = meta->GetIMetadata_I()->RemoveNode( childNode->GetNameSpace(), childNode->GetName() );
				parentArrayNode->InsertNodeAtIndex( childNode, index );
				index = childNode->GetIndex() + 1;
			}
		} else {
			parentArrayNode->InsertNodeAtIndex( parsedNode, contextNode->GetIndex() + 1 );
		}
	}
Example #3
0
void
symcache_init(const char *symcache_dir_in,
              size_t modsize_cache_threshold)
{
    initialized = true;

    op_modsize_cache_threshold = modsize_cache_threshold;

    hashtable_init_ex(&symcache_table, SYMCACHE_MASTER_TABLE_HASH_BITS,
                      IF_WINDOWS_ELSE(HASH_STRING_NOCASE, HASH_STRING),
                      true/*strdup*/, false/*!synch*/,
                      symcache_free_entry, NULL, NULL);
    symcache_lock = dr_mutex_create();

    dr_snprintf(symcache_dir, BUFFER_SIZE_ELEMENTS(symcache_dir), 
                "%s", symcache_dir_in);
    NULL_TERMINATE_BUFFER(symcache_dir);
    if (!dr_directory_exists(symcache_dir)) {
        if (!dr_create_dir(symcache_dir)) {
            /* check again in case of a race (i#616) */
            if (!dr_directory_exists(symcache_dir)) {
                NOTIFY_ERROR("Unable to create symcache dir %s"NL, symcache_dir);
                ASSERT(false, "unable to create symcache dir");
                dr_abort();
            }
        }
    }
}
Example #4
0
	void APICALL DOMParserImpl::ParseWithSpecificAction( const char * buffer, sizet bufferLength, eActionType actionType, spINode & node ) {
		auto parsedNode = ParseAsNode( buffer, bufferLength );

		if ( parsedNode ) {
			switch ( actionType ) {
			case kATAppendAsChildren:
				AppendAsChildren( node, parsedNode );
				break;

			case kATReplaceChildren:
				ReplaceChildren( node, parsedNode );
				break;

			case kATAppendOrReplaceChildren:
				AppendOrReplaceChildren( node, parsedNode );
				break;

			case kATInsertBefore:
				InsertBefore( node, parsedNode );
				break;

			case kATInsertAfter:
				InsertAfter( node, parsedNode );
				break;

			case kATReplace:
				ReplaceNode( node, parsedNode );
				break;

			default:
				NOTIFY_ERROR( IError::kEDGeneral, kGECNotImplemented, "Not yet implemented", IError::kESOperationFatal, true, static_cast< sizet >( actionType ) );
			}

		}
	}
Example #5
0
	static void ReplaceNode( spINode & node, const spINode & parsedNode ) {
		if ( node && node->IsArrayItem() && node->GetNodeType() != parsedNode->GetNodeType() ) {
			NOTIFY_ERROR( IError::kEDDataModel, kDMECArrayItemTypeDifferent, "node type is different than what currently array can hold",
				IError_v1::kESOperationFatal, true, static_cast< sizet >( node->GetNodeType() ), true, static_cast< sizet >( parsedNode->GetNodeType() ) );
		}
		node = parsedNode;
	}
Example #6
0
	static void AppendOrReplaceChildren( const spINode & contextNode, const spINode & parsedNode ) {
		if ( !contextNode )
			NOTIFY_ERROR( IError::kEDParser, kPECInvalidContextNode, "Context Node is invalid", IError::kESOperationFatal, false, false );
		auto contextNodeType = contextNode->GetNodeType();
		if ( contextNodeType != INode::kNTStructure && contextNodeType != INode::kNTArray )
			NOTIFY_ERROR( IError::kEDParser, kPECContextNodeIsNonComposite, "Context Node is non composite", IError::kESOperationFatal,
				true, static_cast< sizet >( contextNodeType ) );
		switch ( contextNodeType ) {
		case INode::kNTArray:
			ReplaceChildren( contextNode->GetInterfacePointer< IArrayNode >(), parsedNode );
			break;

		case INode::kNTStructure:
			AppendOrReplaceChildren( contextNode->GetInterfacePointer< IStructureNode >(), parsedNode );
			break;
		}
	}
Example #7
0
void NotifyError( const char * errorMsg, const uint64 & key, eConfigurableErrorCode errorCode,
                  IConfigurable::eDataType type, T1 v1,
                  IConfigurable::eDataType oldType, T2 v2 )
{
    bool valuePresent = type != IConfigurable::kDTNone;
    bool oldValuePresent = oldType != IConfigurable::kDTNone;
    NOTIFY_ERROR( IError_v1::kEDConfigurable, errorCode, errorMsg, IError_v1::kESOperationFatal,
                  true, key, valuePresent, static_cast< uint64 >( type ), oldValuePresent, static_cast< uint64 >( oldType ),
                  valuePresent, v1, oldValuePresent, v2 );
}
	spINode APICALL ClientDOMParserWrapperImpl::ParseAsNode( const char * buffer, sizet bufferLength ) {
		pcIError_base error( NULL );
		uint32 unknownExceptionCaught( 0 );
		auto pnode = mpClientParser->parse( buffer, bufferLength, this, &ReportErrorAndContinueABISafe, error, unknownExceptionCaught );
		if ( error ) {
			auto spError = IError::MakeShared( error );
			error->Release();
			throw spError;
		}
		if ( unknownExceptionCaught )
			NOTIFY_ERROR( IError::kEDGeneral, kGECUnknownExceptionCaught, "Unknown Exception caught in the client code", IError::kESOperationFatal, false, false );
		return MakeUncheckedSharedPointer( pnode, __FILE__, __LINE__, false );
	}
	eConfigurableErrorCode APICALL ClientDOMSerializerWrapperImpl::ValidateValue( const uint64 & key, eDataType type, const CombinedDataValue & value ) const {
		pcIError_base error( NULL );
		uint32 unknownExceptionCaught( 0 );
		auto retValue = mpSerializer->validate( key, static_cast< uint32 >( type ), value, error, unknownExceptionCaught );
		if ( error ) {
			auto spError = IError::MakeShared( error );
			error->Release();
			throw spError;
		}
		if ( unknownExceptionCaught )
			NOTIFY_ERROR( IError::kEDGeneral, kGECUnknownExceptionCaught, "Unknown Exception caught in the client code", IError::kESOperationFatal, false, false );
		return static_cast< eConfigurableErrorCode >( retValue );
	}
Example #10
0
	bool HandleConstAlias( const spIMetadata & meta, spINode & destNode, const XMP_ExpandedXPath & expandedXPath, sizet & nodeIndex ) {
		if ( expandedXPath.empty() ) NOTIFY_ERROR( IError::kEDGeneral, kGECLogicalError, "Empty XPath", IError::kESOperationFatal, false, false );

		if ( !( expandedXPath[ kSchemaStep ].options & kXMP_SchemaNode ) ) {
			return false;
		} else {
			XMP_VarString namespaceName = expandedXPath[ kSchemaStep ].step.c_str();
			size_t colonPos = expandedXPath[ kRootPropStep ].step.find( ":" );
			assert( colonPos != std::string::npos );
			XMP_VarString propertyName = expandedXPath[ kRootPropStep ].step.substr( colonPos + 1 );

			// here find the node with this name
			destNode = meta->GetNode( namespaceName.c_str(), namespaceName.size(), propertyName.c_str(), propertyName.size() );
			if ( !destNode ) return false;
			if ( expandedXPath.size() == 2 ) return true;
			assert( destNode->GetNodeType() == INode::kNTArray );

			if ( expandedXPath[ 2 ].options == kXMP_ArrayIndexStep ) {
				assert( expandedXPath[ 2 ].step == "[1]" );
				destNode = destNode->ConvertToArrayNode()->GetNodeAtIndex( 1 );
				auto actualNodeType = destNode->GetNodeType();
				if ( destNode ) {
					if ( nodeIndex ) nodeIndex = 1;
					return true;
				}
				return false;
			} else if ( expandedXPath[ 2 ].options == kXMP_QualSelectorStep ) {
				assert( expandedXPath[ 2 ].step == "[?xml:lang=\"x-default\"]" );
				if ( !destNode || destNode->GetNodeType() != INode::kNTArray ) return false;
				spINodeIterator iter = destNode->ConvertToArrayNode()->Iterator();
				sizet index = 1;
				while ( iter ) {
					spINode node = iter->GetNode();
					try {
						spISimpleNode qualNode = node->GetSimpleQualifier( "http://www.w3.org/XML/1998/namespace", AdobeXMPCommon::npos, "lang", AdobeXMPCommon::npos );
						if ( qualNode->GetValue()->compare( "x-default" ) == 0 ) {
							destNode = node;
							if ( nodeIndex ) nodeIndex = index;
							return true;
						}
					} catch ( spcIError err ) {

					} catch ( ... ) {}
					index++;
					iter = iter->Next();
				}
				return false;
			}
			return false;
		}
	}
Example #11
0
bool ConfigurableImpl::GetParameter( const uint64 & actualKey, eDataType type, CombinedDataValue & value ) const {
    uint64 key = ModifyKey( actualKey );
    if ( mTreatKeyAsCaseInsensitiveCharBuffer )
        key = ConvertToLowerCase( key );
    AutoSharedLock lock( GetMutex() );
    auto it = mMap.find( key );
    if ( it == mMap.end() )
        return false;
    if ( it->second.first != type ) {
        NOTIFY_ERROR( IError_v1::kEDConfigurable, kCECValueTypeMismatch,
                      "Type mismatch for a parameter", IError_v1::kESOperationFatal,
                      true, key, true, static_cast< uint64 >( it->second.first ), true, static_cast< uint64 >( type ) );
        return false;
    }
    value = it->second.second;
    return true;
}
	ClientDOMSerializerWrapperImpl::ClientDOMSerializerWrapperImpl( pIClientDOMSerializer serializer )
		: mpSerializer( serializer )
	{
		if ( serializer ) {
			pcIError_base error( NULL );
			uint32 unknownExceptionCaught( 0 );
			TreatKeyAsCaseInsensitive( serializer->areKeysCaseSensitive( error, unknownExceptionCaught ) == 0 );
			if ( !error && unknownExceptionCaught == 0 )
				serializer->initialize( this, error, unknownExceptionCaught );
			if ( error ) {
				auto spError = IError::MakeShared( error );
				error->Release();
				throw spError;
			}
			if ( unknownExceptionCaught )
				NOTIFY_ERROR( IError::kEDGeneral, kGECUnknownExceptionCaught, "Unknown Exception caught in the client code", IError::kESOperationFatal, false, false );
		}
	}
	spIUTF8String APICALL ClientDOMSerializerWrapperImpl::Serialize( const spINode & node, const spcINameSpacePrefixMap & map ) {
		spIUTF8String str( IUTF8String_I::CreateUTF8String( NULL, 0 ) );
		pcIError_base error( NULL );
		uint32 unknownExceptionCaught( 0 );
		spcINameSpacePrefixMap mergedMap = INameSpacePrefixMap::GetDefaultNameSpacePrefixMap();

		if ( map ) {
			spINameSpacePrefixMap newMergedMap = mergedMap->Clone();
			newMergedMap->GetINameSpacePrefixMap_I()->Merge( map );
			mergedMap = newMergedMap;
		}

		mpSerializer->serialize( node ? node->GetActualINode() : NULL, mergedMap ? mergedMap->GetActualINameSpacePrefixMap() : NULL, this,
			&ReportErrorAndContinueABISafe, str->GetActualIUTF8String(), error, unknownExceptionCaught );
		if ( error ) {
			auto spError = IError::MakeShared( error );
			error->Release();
			throw spError;
		}
		if ( unknownExceptionCaught )
			NOTIFY_ERROR( IError::kEDGeneral, kGECUnknownExceptionCaught, "Unknown Exception caught in the client code", IError::kESOperationFatal, false, false );
		return str;
	}
Example #14
0
	spIMetadata APICALL DOMParserImpl::Parse( const char * buffer, sizet bufferLength ) {
		auto node = ParseAsNode( buffer, bufferLength );
		if ( node ) {
			switch ( node->GetNodeType() ) {
			case INode::kNTSimple:
			case INode::kNTArray:
				{
					spIMetadata meta = IMetadata::CreateMetadata();
					meta->AppendNode( node );
					return meta;
				}
				break;

			case INode::kNTStructure:
				{
					pIMetadata meta( NULL );
					try {
						meta = node->GetInterfacePointer< IMetadata >();
					} catch ( spcIError err ) {
						meta = NULL;
					}
					if ( meta ) {
						return MakeUncheckedSharedPointer( meta, __FILE__, __LINE__ );
					} else {
						spIMetadata meta = IMetadata::CreateMetadata();
						meta->AppendNode( node );
						return meta;
					}
				}
				break;

			default:
				NOTIFY_ERROR( IError::kEDGeneral, kGECInternalFailure, "Unhandled situation occured", IError::kESOperationFatal, false, false );
			}
		}
		return spIMetadata();
	}
Example #15
0
	spINode APICALL MetadataImpl::ReplaceNode( const spINode & node ) {
		if ( mSupportAliases  ) {
			XMP_ExpandedXPath exPath;
			QualifiedName qName( node->GetNameSpace(), node->GetName() );
			bool nodeIsAlias = IsNodeAlias( node->GetNameSpace()->c_str(), node->GetName()->c_str(), exPath );
			if ( nodeIsAlias ) {
				spINode actualNodeToBeRemoved;
				sizet nodeIndex = 0;
				auto spSelf = MakeUncheckedSharedPointer( this, __FILE__, __LINE__, false );
				if ( HandleConstAlias( spSelf, actualNodeToBeRemoved, exPath, nodeIndex ) ) {
					qName = QualifiedName( actualNodeToBeRemoved->GetNameSpace(), actualNodeToBeRemoved->GetName() );
				}
			}

			if ( CheckSuitabilityToBeUsedAsChildNode( node ) && GetNode( qName.mNameSpace, qName.mName ) ) {
				auto retValue = RemoveNode( qName.mNameSpace, qName.mName );
				spINode destNode = node;
				if ( nodeIsAlias ) {
					sizet destNodeIndex = 0;
					auto spSelf = MakeUncheckedSharedPointer( this, __FILE__, __LINE__, false );
					if ( !HandleNonConstAlias( spSelf, exPath, true, 0, destNode, destNodeIndex, false, node ) ) {
						return destNode;
					}
				}
				InsertNode( destNode );
				return retValue;
			} else {
				NOTIFY_ERROR( IError_v1::kEDDataModel, kDMECNoSuchNodeExists,
					"no such node exists with the specified qualified name", IError_v1::kESOperationFatal,
					true, node->GetNameSpace(), true, node->GetName() );
			}
			return spINode();
		} else {
			return StructureNodeImpl::ReplaceNode( node );
		}
	}
Example #16
0
	bool HandleNonConstAlias( const spIMetadata & meta, XMP_ExpandedXPath & expandedXPath, bool createNodes, XMP_OptionBits leafOptions, spINode & destNode, sizet & nodeIndex, bool ignoreLastStep, const spINode & inputNode ) {
		destNode = meta;
		spcIUTF8String inputNodeValue;
		if ( inputNode && inputNode->GetNodeType() == INode::kNTSimple ) {

			inputNodeValue = inputNode->ConvertToSimpleNode()->GetValue();
		}
		bool isAliasBeingCreated = expandedXPath.size() == 2;
		if ( expandedXPath.empty() )
			NOTIFY_ERROR( IError::kEDDataModel, kDMECBadXPath, "Empty XPath", IError::kESOperationFatal, false, false );
		if ( !( expandedXPath[ kSchemaStep ].options & kXMP_SchemaNode ) ) {
			return false;
		} else {
			XMP_VarString namespaceName = expandedXPath[ kSchemaStep ].step.c_str();
			size_t colonPos = expandedXPath[ kRootPropStep ].step.find( ":" );
			assert( colonPos != std::string::npos );
			XMP_VarString propertyName = expandedXPath[ kRootPropStep ].step.substr( colonPos + 1 );
			spcINode childNode = meta->GetNode( namespaceName.c_str(), namespaceName.size(), propertyName.c_str(), propertyName.size() );
			if ( !childNode && !createNodes ) return false;
			if ( expandedXPath.size() == 2 ) {
				if ( childNode ) return true;
				XMP_OptionBits createOptions = 0;
				spINode tempNode;
				if ( isAliasBeingCreated ) tempNode = CreateTerminalNode( namespaceName.c_str(), propertyName.c_str(), leafOptions );
				else  tempNode = CreateTerminalNode( namespaceName.c_str(), propertyName.c_str(), createOptions );
				if ( !tempNode ) return false;
				if ( inputNodeValue ) tempNode->ConvertToSimpleNode()->SetValue( inputNodeValue->c_str(), inputNodeValue->size() );
				if ( destNode == meta ) {
					meta->InsertNode( tempNode );
				} else {
					destNode->ConvertToStructureNode()->AppendNode( tempNode );
				}
				destNode = tempNode;
				if ( destNode ) return true;
				return false;
			}

			XMP_Assert( expandedXPath.size() == 3 );
			if ( expandedXPath[ 2 ].options == kXMP_ArrayIndexStep ) {
				XMP_Assert( expandedXPath[ 2 ].step == "[1]" );
				destNode = meta->GetNode( namespaceName.c_str(), namespaceName.size(), propertyName.c_str(), propertyName.size() );
				if ( !destNode && !createNodes ) return false;
				if ( !destNode ) {
					spINode arrayNode = CreateTerminalNode( namespaceName.c_str(), propertyName.c_str(), kXMP_PropArrayIsOrdered | kXMP_PropValueIsArray );
					meta->AppendNode( arrayNode );
					destNode = arrayNode;
				}

				if ( destNode->ConvertToArrayNode()->GetNodeAtIndex( 1 ) ) {
					destNode = destNode->ConvertToArrayNode()->GetNodeAtIndex( 1 );
					if ( nodeIndex ) nodeIndex = 1;
					return true;
				} else {
					spISimpleNode indexNode = ISimpleNode::CreateSimpleNode( namespaceName.c_str(), namespaceName.size(), propertyName.c_str(), propertyName.size() );
					if ( inputNodeValue ) {
						indexNode->SetValue( inputNodeValue->c_str(), inputNodeValue->size() );
					}
					destNode->ConvertToArrayNode()->InsertNodeAtIndex( indexNode, 1 );
					destNode = indexNode;
					return true;
				}
				return false;
			} else if ( expandedXPath[ 2 ].options == kXMP_QualSelectorStep ) {
				assert( expandedXPath[ 2 ].step == "[?xml:lang=\"x-default\"]" );
				destNode = meta->GetNode( namespaceName.c_str(), namespaceName.size(), propertyName.c_str(), propertyName.size() );
				if ( !destNode && !createNodes ) return false;
				spINode arrayNode = CreateTerminalNode( namespaceName.c_str(), propertyName.c_str(), kXMP_PropValueIsArray | kXMP_PropArrayIsAltText);
				meta->AppendNode( arrayNode );
				destNode = arrayNode;
				auto iter = destNode->ConvertToArrayNode()->Iterator();
				XMP_Index index = 1;
				while ( iter ) {
					spINode node = iter->GetNode();
					spINode qualNode = node->GetQualifier( "http://www.w3.org/XML/1998/namespace", AdobeXMPCommon::npos, "lang", AdobeXMPCommon::npos );
					if ( qualNode->GetNodeType() == INode::kNTSimple ) {
						if ( !qualNode->ConvertToSimpleNode()->GetValue()->compare( "x-default" ) ) {
							destNode = node;
							if ( nodeIndex ) nodeIndex = index;
							return true;
						}
					}
					index++;
					iter = iter->Next();
				}
				spISimpleNode qualifierNode = ISimpleNode::CreateSimpleNode( "http://www.w3.org/XML/1998/namespace", AdobeXMPCommon::npos, "lang", AdobeXMPCommon::npos, "x-default", AdobeXMPCommon::npos );
				if ( destNode->ConvertToArrayNode()->GetNodeAtIndex( 1 ) ) {
					destNode = destNode->ConvertToArrayNode()->GetNodeAtIndex( 1 );
					if ( nodeIndex ) nodeIndex = 1;
					destNode->InsertQualifier( qualifierNode );
					return true;
				} else {
					spISimpleNode indexNode = ISimpleNode::CreateSimpleNode( namespaceName.c_str(), AdobeXMPCommon::npos, propertyName.c_str(), AdobeXMPCommon::npos );
					if ( inputNodeValue ) {
						indexNode->SetValue( inputNodeValue->c_str(), inputNodeValue->size() );
					}
					destNode->ConvertToArrayNode()->InsertNodeAtIndex( indexNode, 1 );
					destNode->InsertQualifier( qualifierNode );
					destNode = indexNode;
					return true;
				}
			}
		}
		return false;
	}
Example #17
0
DR_EXPORT
drmf_status_t
drsymcache_init(client_id_t client_id,
                const char *symcache_dir_in,
                size_t modsize_cache_threshold)
{
#ifdef WINDOWS
    module_data_t *mod;
#endif
    drmf_status_t res;
    drmgr_priority_t pri_mod_load_cache =
        {sizeof(pri_mod_load_cache), DRMGR_PRIORITY_NAME_DRSYMCACHE, NULL, NULL,
         DRMGR_PRIORITY_MODLOAD_DRSYMCACHE_READ};
    drmgr_priority_t pri_mod_unload_cache =
        {sizeof(pri_mod_unload_cache), DRMGR_PRIORITY_NAME_DRSYMCACHE, NULL, NULL,
         DRMGR_PRIORITY_MODUNLOAD_DRSYMCACHE};
    drmgr_priority_t pri_mod_save_cache =
        {sizeof(pri_mod_save_cache), DRMGR_PRIORITY_NAME_DRSYMCACHE_SAVE, NULL, NULL,
         DRMGR_PRIORITY_MODLOAD_DRSYMCACHE_SAVE};

    /* handle multiple sets of init/exit calls */
    int count = dr_atomic_add32_return_sum(&symcache_init_count, 1);
    if (count > 1)
        return DRMF_WARNING_ALREADY_INITIALIZED;

    res = drmf_check_version(client_id);
    if (res != DRMF_SUCCESS)
        return res;

    drmgr_init();
    drmgr_register_module_load_event_ex(symcache_module_load, &pri_mod_load_cache);
    drmgr_register_module_unload_event_ex(symcache_module_unload, &pri_mod_unload_cache);
    drmgr_register_module_load_event_ex(symcache_module_load_save, &pri_mod_save_cache);

    initialized = true;

    op_modsize_cache_threshold = modsize_cache_threshold;

    hashtable_init_ex(&symcache_table, SYMCACHE_MASTER_TABLE_HASH_BITS,
                      IF_WINDOWS_ELSE(HASH_STRING_NOCASE, HASH_STRING),
                      true/*strdup*/, false/*!synch*/,
                      symcache_free_entry, NULL, NULL);
    symcache_lock = dr_mutex_create();

    dr_snprintf(symcache_dir, BUFFER_SIZE_ELEMENTS(symcache_dir),
                "%s", symcache_dir_in);
    NULL_TERMINATE_BUFFER(symcache_dir);
    if (!dr_directory_exists(symcache_dir)) {
        if (!dr_create_dir(symcache_dir)) {
            /* check again in case of a race (i#616) */
            if (!dr_directory_exists(symcache_dir)) {
                NOTIFY_ERROR("Unable to create symcache dir %s"NL, symcache_dir);
                ASSERT(false, "unable to create symcache dir");
                dr_abort();
            }
        }
    }

#ifdef WINDOWS
    /* It's common for tools to query ntdll in their init routines so we add it
     * early here
     */
    mod = dr_lookup_module_by_name("ntdll.dll");
    if (mod != NULL) {
        symcache_module_load(dr_get_current_drcontext(), mod, true);
        dr_free_module_data(mod);
    }
#endif

    return DRMF_SUCCESS;
}
Example #18
0
/* Sets modcache->has_debug_info.
 * No lock is needed as we assume the caller hasn't exposed modcache outside this
 * thread yet.
 */
static bool
symcache_read_symfile(const module_data_t *mod, const char *modname,
                      mod_cache_t *modcache)
{
    hashtable_t *symtable = &modcache->table;
    bool res = false;
    const char *line, *next_line;
    char symbol[MAX_SYMLEN];
    size_t offs;
    uint64 map_size;
    size_t actual_size;
    bool ok;
    void *map = NULL;
    char symfile[MAXIMUM_PATH];
    file_t f;

    symcache_get_filename(modname, symfile, BUFFER_SIZE_ELEMENTS(symfile));
    f = dr_open_file(symfile, DR_FILE_READ);
    if (f == INVALID_FILE)
        goto symcache_read_symfile_done;
    LOG(2, "processing symbol cache file for %s\n", modname);
    /* we avoid having to do our own buffering by just mapping the whole file */
    ok = dr_file_size(f, &map_size);
    if (ok) {
        actual_size = (size_t) map_size;
        ASSERT(actual_size == map_size, "file size too large");
        map = dr_map_file(f, &actual_size, 0, NULL, DR_MEMPROT_READ, 0);
    }
    if (!ok || map == NULL || actual_size < map_size) {
        NOTIFY_ERROR("Error mapping symcache file for %s"NL, modname);
        goto symcache_read_symfile_done;
    }
    if (strncmp((char *)map, SYMCACHE_FILE_HEADER, strlen(SYMCACHE_FILE_HEADER)) != 0) {
        WARN("WARNING: symbol cache file is corrupted\n");
        goto symcache_read_symfile_done;
    }
    /* i#1057: We use dr_sscanf() because sscanf() from ntdll will call strlen()
     * and read off the end of the mapped file if it doesn't hit a null.
     */
    if (dr_sscanf((char *)map + strlen(SYMCACHE_FILE_HEADER) + 1, "%d",
                  (uint *)&offs) != 1 ||
        /* neither forward nor backward compatible */
        offs != SYMCACHE_VERSION) {
        WARN("WARNING: symbol cache file has wrong version\n");
        goto symcache_read_symfile_done;
    }
    line = strchr((char *) map, '\n');
    if (line != NULL)
        line++;

    if (line != NULL) {
        /* Module consistency checks */
        uint cache_file_size;
        uint64 module_file_size;
        uint timestamp;
#ifdef WINDOWS
        version_number_t file_version;
        version_number_t product_version;
        uint checksum;
        size_t module_internal_size;
        if (dr_sscanf(line, "%u,"UINT64_FORMAT_STRING","UINT64_FORMAT_STRING","
                      UINT64_FORMAT_STRING",%u,%u,%lu",
                      &cache_file_size, &module_file_size, &file_version.version,
                      &product_version.version, &checksum, &timestamp,
                      &module_internal_size) != 7) {
            WARN("WARNING: %s symbol cache file has bad consistency header\n", modname);
            goto symcache_read_symfile_done;
        }
        if (module_file_size != modcache->module_file_size ||
            file_version.version != modcache->file_version.version ||
            product_version.version != modcache->product_version.version ||
            checksum != modcache->checksum ||
            timestamp != modcache->timestamp ||
            module_internal_size != modcache->module_internal_size) {
            LOG(1, "module version mismatch: %s symbol cache file is stale\n", modname);
            LOG(2, "\t"UINT64_FORMAT_STRING" vs "UINT64_FORMAT_STRING", "
                UINT64_FORMAT_STRING" vs "UINT64_FORMAT_STRING", "
                UINT64_FORMAT_STRING" vs "UINT64_FORMAT_STRING", "
                "%u vs %u, %u vs %u, %lu vs %lu\n",
                module_file_size, modcache->module_file_size,
                file_version.version, modcache->file_version.version,
                product_version.version, modcache->product_version.version,
                checksum, modcache->checksum,
                timestamp, modcache->timestamp,
                module_internal_size, modcache->module_internal_size);
            goto symcache_read_symfile_done;
        }
#elif defined(LINUX)
        if (dr_sscanf(line, "%u,"UINT64_FORMAT_STRING",%u",
                      &cache_file_size, &module_file_size, &timestamp) != 3) {
            WARN("WARNING: %s symbol cache file has bad consistency header\n", modname);
            goto symcache_read_symfile_done;
        }
        if (module_file_size != modcache->module_file_size ||
            timestamp != modcache->timestamp) {
            LOG(1, "module version mismatch: %s symbol cache file is stale\n", modname);
            goto symcache_read_symfile_done;
        }
#elif defined(MACOS)
        uint current_version;
        uint compatibility_version;
        byte uuid[16];
        /* XXX: if dr_sscanf supported %n maybe we could split these into
         * separate scans on the same string and share code w/ Linux.
         */
        if (dr_sscanf(line, "%u,"UINT64_FORMAT_STRING",%u,%u,%u,%x,%x,%x,%x",
                      &cache_file_size, &module_file_size, &timestamp,
                      &current_version, &compatibility_version,
                      (uint*)(&uuid[0]), (uint*)(&uuid[4]),
                      (uint*)(&uuid[8]), (uint*)(&uuid[12])) != 9) {
            WARN("WARNING: %s symbol cache file has bad consistency header B\n", modname);
            goto symcache_read_symfile_done;
        }
        if (current_version != modcache->current_version ||
            compatibility_version != modcache->compatibility_version ||
            memcmp(uuid, modcache->uuid, sizeof(uuid)) != 0) {
            LOG(1, "module version mismatch: %s symbol cache file is stale\n", modname);
            goto symcache_read_symfile_done;
        }
#endif
        /* We could go further w/ CRC or even MD5 but not worth it for dev tool */
        if (cache_file_size != (uint)map_size) {
            WARN("WARNING: %s symbol cache file is corrupted: map=%d vs file=%d\n",
                 modname, (uint)map_size, cache_file_size);
            goto symcache_read_symfile_done;
        }
    }
    line = strchr(line, '\n');
    if (line != NULL)
        line++;
    if (line != NULL) {
        uint has_debug_info;
        if (dr_sscanf(line, "%u", &has_debug_info) != 1) {
            WARN("WARNING: %s symbol cache file has bad consistency header\n", modname);
            goto symcache_read_symfile_done;
        }
        if (has_debug_info) {
            /* We assume that the current availability of debug info doesn't matter */
            modcache->has_debug_info = true;
        } else {
            /* We delay the costly check for symbols until we've read the symcache
             * b/c if its entry indicates symbols we don't need to look
             */
            if (module_has_symbols(mod)) {
                LOG(1, "module now has debug info: %s symbol cache is stale\n", modname);
                goto symcache_read_symfile_done;
            }
        }
    }
    line = strchr(line, '\n');
    if (line != NULL)
        line++;

    symbol[0] = '\0';
    for (; line != NULL && line < ((char *)map) + map_size; line = next_line) {
        const char *comma = strchr(line, ',');
        const char *newline = strchr(line, '\n');
        size_t symlen = (comma != NULL ? comma - line : 0);
        if (newline == NULL) {
            next_line = ((char *)map) + map_size + 1; /* handle EOF w/o trailing \n */
        } else {
            next_line = newline + 1;
        }
        if (symlen > 0 && symlen < MAX_SYMLEN) {
            strncpy(symbol, line, symlen);
            symbol[symlen] = '\0';
        }
        if (comma != NULL && symlen < MAX_SYMLEN && symbol[0] != '\0' &&
            dr_sscanf(comma, ",0x%x", (uint *)&offs) == 1) {
#ifdef WINDOWS
            /* Guard against corrupted files that cause DrMem to crash (i#1465) */
            if (offs >= modcache->module_internal_size) {
                /* This one we want to know about */
                NOTIFY("SYMCACHE ERROR: %s file has too-large entry "PIFX" for %s"NL,
                       modname, offs, symbol);
                goto symcache_read_symfile_done;
            }
#endif
            symcache_symbol_add(modname, symtable, symbol, offs);
        } else {
            WARN("WARNING: malformed symbol cache line \"%.*s\"\n",
                 next_line - line - 1, line);
            /* We abort in case there were two dueling writes to the file
             * and it somehow got past the self-consistency check,
             * putting a header in the middle of the file, and we can't
             * trust subsequent lines since they may belong to a different
             * version of the module
             */
            break; /* res should still be true */
        }
    }
    res = true;
 symcache_read_symfile_done:
    if (map != NULL)
        dr_unmap_file(map, actual_size);
    if (f != INVALID_FILE)
        dr_close_file(f);
    if (!res)
        modcache->has_debug_info = module_has_symbols(mod);

    return res;
}
Example #19
0
/* caller must hold symcache_lock */
static void
symcache_write_symfile(const char *modname, mod_cache_t *modcache)
{
    uint i;
    file_t f;
    hashtable_t *symtable = &modcache->table;
    char buf[SYMCACHE_BUFFER_SIZE];
    size_t sofar = 0;
    ssize_t len;
    size_t bsz = BUFFER_SIZE_ELEMENTS(buf);
    size_t filesz_loc;
    char symfile[MAXIMUM_PATH];
    char symfile_tmp[MAXIMUM_PATH];
    int64 file_size;

    ASSERT(dr_mutex_self_owns(symcache_lock), "missing symcache lock");

    /* if from file, we assume it's a waste of time to re-write file:
     * the version matched after all, unless we appended to it.
     */
    if (modcache->from_file && !modcache->appended)
        return;
    if (symtable->entries == 0)
        return; /* nothing to write */

    /* Open the temp symcache that we will rename.  */
    symcache_get_filename(modname, symfile, BUFFER_SIZE_ELEMENTS(symfile));
    f = INVALID_FILE;
    i = 0;
    while (f == INVALID_FILE && i < SYMCACHE_MAX_TMP_TRIES) {
        dr_snprintf(symfile_tmp, BUFFER_SIZE_ELEMENTS(symfile_tmp),
                    "%s.%04d.tmp", symfile, i);
        NULL_TERMINATE_BUFFER(symfile_tmp);
        f = dr_open_file(symfile_tmp, DR_FILE_WRITE_REQUIRE_NEW);
        i++;
    }
    if (f == INVALID_FILE) {
        NOTIFY("WARNING: Unable to create symcache temp file %s"NL,
               symfile_tmp);
        return;
    }

    BUFFERED_WRITE(f, buf, bsz, sofar, len, "%s %d\n",
                   SYMCACHE_FILE_HEADER, SYMCACHE_VERSION);
    /* Leave room for file size for self-consistency check */
    filesz_loc = sofar;  /* XXX: Assumes that the buffer hasn't been flushed. */
    BUFFERED_WRITE(f, buf, bsz, sofar, len,
                   "%"STRINGIFY(SYMCACHE_SIZE_DIGITS)"u,", 0);
#ifdef WINDOWS
    BUFFERED_WRITE(f, buf, bsz, sofar, len,
                   UINT64_FORMAT_STRING","UINT64_FORMAT_STRING","
                   UINT64_FORMAT_STRING",%u,%u,%lu\n",
                   modcache->module_file_size, modcache->file_version.version,
                   modcache->product_version.version,
                   modcache->checksum, modcache->timestamp,
                   modcache->module_internal_size);
#else
    BUFFERED_WRITE(f, buf, bsz, sofar, len, UINT64_FORMAT_STRING",%u",
                   modcache->module_file_size, modcache->timestamp);
# ifdef MACOS
    BUFFERED_WRITE(f, buf, bsz, sofar, len, ",%u,%u,",
                   modcache->current_version, modcache->compatibility_version);
    /* For easy sscanf we print as 4 ints */
    for (i = 0; i < 4; i++)
        BUFFERED_WRITE(f, buf, bsz, sofar, len, "%08x,", *(int*)(&modcache->uuid[i*4]));
# endif
    BUFFERED_WRITE(f, buf, bsz, sofar, len, "\n");
#endif
    BUFFERED_WRITE(f, buf, bsz, sofar, len, "%u\n", modcache->has_debug_info);
    for (i = 0; i < HASHTABLE_SIZE(symtable->table_bits); i++) {
        hash_entry_t *he;
        for (he = symtable->table[i]; he != NULL; he = he->next) {
            offset_list_t *olist = (offset_list_t *) he->payload;
            offset_entry_t *e;
            if (olist == NULL)
                continue;
            /* skip symbol in dup entries to save space */
            BUFFERED_WRITE(f, buf, bsz, sofar, len, "%s", he->key);
            e = olist->list;
            while (e != NULL) {
                BUFFERED_WRITE(f, buf, bsz, sofar, len, ",0x%x\n", e->offs);
                e = e->next;
            }
        }
    }

    /* now update size */
    FLUSH_BUFFER(f, buf, sofar);
    if ((file_size = dr_file_tell(f)) < 0 ||
        dr_snprintf(buf, BUFFER_SIZE_ELEMENTS(buf),
                    "%"STRINGIFY(SYMCACHE_SIZE_DIGITS)"u", (uint)file_size) < 0 ||
        !dr_file_seek(f, filesz_loc, DR_SEEK_SET) ||
        dr_write_file(f, buf, SYMCACHE_SIZE_DIGITS) != SYMCACHE_SIZE_DIGITS) {
        /* If any steps fail, warn and give up. */
        NOTIFY("WARNING: Unable to write symcache file size."NL);
        dr_close_file(f);
        dr_delete_file(symfile_tmp);
        return;
    } else {
        LOG(3, "Wrote symcache %s file size %u to pos "SZFMT"\n",
            modname, (uint)file_size, filesz_loc);
        ASSERT(strlen(buf) <= SYMCACHE_SIZE_DIGITS, "not enough space for file size");
    }

    dr_close_file(f);

    if (!dr_rename_file(symfile_tmp, symfile, /*replace*/true)) {
        NOTIFY_ERROR("WARNING: Failed to rename the symcache file."NL);
        dr_delete_file(symfile_tmp);
    }
}
Example #20
0
/* If an entry already exists and is 0, replaces it; else adds a new
 * offset for that symbol.
 *
 * If symtable is visible outside of this thread, the caller must hold symcache_lock.
 */
static bool
symcache_symbol_add(const char *modname, hashtable_t *symtable,
                    const char *symbol, size_t offs)
{
    offset_list_t *olist;
    offset_entry_t *e;
    olist = (offset_list_t *) hashtable_lookup(symtable, (void *)symbol);
    if (olist != NULL) {
        if (olist->num == 1 && olist->list->offs == 0) {
            /* replace a single 0 entry */
            if (olist->table != NULL) {
                ASSERT(olist->num >= OFFSET_LIST_MIN_TABLE, "table should be NULL");
                hashtable_remove(olist->table, (void *)(olist->list->offs + 1));
                hashtable_add(olist->table, (void *)(offs + 1), (void *)(offs + 1));
            }
            olist->list->offs = offs;
            return true;
        } else if (olist->num == 1 && offs == 0) {
            /* XXX i#1465: temporary fatal error sanity check as we try to diagnose
             * our symbol cache errors.
             */
            NOTIFY_ERROR("SYMCACHE ERROR: appending 0 to non-0 for %s!%s"NL,
                         modname, symbol);
            dr_abort(); /* make sure we see this on bots */
        }
        if (olist->table != NULL) {
            if (hashtable_lookup(olist->table, (void *)(offs + 1)) != NULL) {
                LOG(2, "%s: ignoring dup entry %s\n", __FUNCTION__, symbol);
                return false;
            }
        } else {
            for (e = olist->list; e != NULL; e = e->next) {
                if (e->offs == offs) {
                    LOG(2, "%s: ignoring dup entry %s\n", __FUNCTION__, symbol);
                    return false;
                }
            }
        }
    } else {
        olist = (offset_list_t *) global_alloc(sizeof(*olist), HEAPSTAT_HASHTABLE);
        olist->num = 0;
        olist->list = NULL;
        olist->list_last = NULL;
        olist->table = NULL;
    }
    LOG(2, "%s: %s \"%s\" @ "PIFX"\n", __FUNCTION__, modname, symbol, offs);
    /* we could verify by an addr lookup but we still need consistency info
     * in the file for the negative entries so we don't bother
     */
    e = (offset_entry_t *) global_alloc(sizeof(*e), HEAPSTAT_HASHTABLE);
    e->offs = offs;
    e->next = NULL;
    /* append to avoid affecting iteration */
    if (olist->list_last == NULL) {
        ASSERT(olist->list == NULL, "last not set");
        olist->list = e;
        olist->list_last = e;
    } else {
        olist->list_last->next = e;
        olist->list_last = e;
    }
    olist->num++;
    if (olist->num >= OFFSET_LIST_MIN_TABLE) {
        if (olist->table == NULL) {
            /* enough entries that a table is worthwhile */
            olist->table = (hashtable_t *)
                global_alloc(sizeof(*olist->table), HEAPSTAT_HASHTABLE);
            hashtable_init(olist->table, SYMCACHE_OLIST_TABLE_HASH_BITS,
                           HASH_INTPTR, false/*strdup*/);
            for (e = olist->list; e != NULL; e = e->next)
                hashtable_add(olist->table, (void *)(e->offs + 1), (void *)(e->offs + 1));
        } else
            hashtable_add(olist->table, (void *)(offs + 1), (void *)(offs + 1));
    }
    hashtable_add(symtable, (void *)symbol, (void *)olist);
    /* clear any cached values */
    olist->iter_idx = 0;
    olist->iter_entry = NULL;
    return true;
}
Example #21
0
static bool
symcache_read_symfile(const module_data_t *mod, const char *modname, mod_cache_t *modcache)
{
    hashtable_t *symtable = &modcache->table;
    bool res = false;
    const char *line, *next_line;
    char symbol[MAX_SYMLEN];
    size_t offs;
    uint64 map_size;
    size_t actual_size;
    bool ok;
    void *map = NULL;
    char symfile[MAXIMUM_PATH];
    file_t f;

    symcache_get_filename(modname, symfile, BUFFER_SIZE_ELEMENTS(symfile));
    f = dr_open_file(symfile, DR_FILE_READ);
    if (f == INVALID_FILE)
        return res;
    LOG(2, "processing symbol cache file for %s\n", modname);
    /* we avoid having to do our own buffering by just mapping the whole file */
    ok = dr_file_size(f, &map_size);
    if (ok) {
        actual_size = (size_t) map_size;
        ASSERT(actual_size == map_size, "file size too large");
        map = dr_map_file(f, &actual_size, 0, NULL, DR_MEMPROT_READ, 0);
    }
    if (!ok || map == NULL || actual_size < map_size) {
        NOTIFY_ERROR("Error mapping symcache file for %s"NL, modname);
        goto symcache_read_symfile_done;
    }
    if (strncmp((char *)map, SYMCACHE_FILE_HEADER, strlen(SYMCACHE_FILE_HEADER)) != 0) {
        WARN("WARNING: symbol cache file is corrupted\n");
        goto symcache_read_symfile_done;
    }
    if (sscanf((char *)map + strlen(SYMCACHE_FILE_HEADER) + 1, "%d", &offs) != 1 ||
        /* neither forward nor backward compatible */
        offs != SYMCACHE_VERSION) {
        WARN("WARNING: symbol cache file has wrong version\n");
        goto symcache_read_symfile_done;
    }
    line = strchr((char *) map, '\n');
    if (line != NULL)
        line++;

    if (line != NULL) {
        /* Module consistency checks */
        uint cache_file_size;
        uint64 module_file_size;
#ifdef WINDOWS
        version_number_t file_version;
        version_number_t product_version;
        uint checksum;
        uint timestamp;
        size_t module_internal_size;
        if (sscanf(line, " %u,"UINT64_FORMAT_STRING","UINT64_FORMAT_STRING","
                   UINT64_FORMAT_STRING",%u,%u,%lu",
                   &cache_file_size, &module_file_size, &file_version.version,
                   &product_version.version, &checksum, &timestamp,
                   &module_internal_size) != 7) {
            WARN("WARNING: %s symbol cache file has bad consistency header\n", modname);
            goto symcache_read_symfile_done;
        }
        if (module_file_size != modcache->module_file_size ||
            file_version.version != modcache->file_version.version ||
            product_version.version != modcache->product_version.version ||
            checksum != modcache->checksum ||
            timestamp != modcache->timestamp ||
            module_internal_size != modcache->module_internal_size) {
            LOG(1, "module version mismatch: %s symbol cache file is stale\n", modname);
            LOG(2, "\t"UINT64_FORMAT_STRING" vs "UINT64_FORMAT_STRING", "
                UINT64_FORMAT_STRING" vs "UINT64_FORMAT_STRING", "
                UINT64_FORMAT_STRING" vs "UINT64_FORMAT_STRING", "
                "%u vs %u, %u vs %u, %lu vs %lu\n",
                module_file_size, modcache->module_file_size,
                file_version.version, modcache->file_version.version,
                product_version.version, modcache->product_version.version,
                checksum, modcache->checksum,
                timestamp, modcache->timestamp,
                module_internal_size, modcache->module_internal_size);
            goto symcache_read_symfile_done;
        }
#else
        if (sscanf(line, "%u,"UINT64_FORMAT_STRING,
                   &cache_file_size, &module_file_size) != 2) {
            WARN("WARNING: %s symbol cache file has bad consistency header\n", modname);
            goto symcache_read_symfile_done;
        }
        if (module_file_size != modcache->module_file_size) {
            LOG(1, "module version mismatch: %s symbol cache file is stale\n", modname);
            goto symcache_read_symfile_done;
        }
#endif
        /* We could go further w/ CRC or even MD5 but not worth it for dev tool */
        if (cache_file_size != (uint)map_size) {
            WARN("WARNING: %s symbol cache file is corrupted\n", modname);
            goto symcache_read_symfile_done;
        }
    }
    line = strchr(line, '\n');
    if (line != NULL)
        line++;

    symbol[0] = '\0';
    for (; line != NULL && line < ((char *)map) + map_size; line = next_line) {
        const char *newline = strchr(line, '\n');
        if (newline == NULL) {
            next_line = ((char *)map) + map_size + 1; /* handle EOF w/o trailing \n */
        } else {
            next_line = newline + 1;
        }
        if (sscanf(line, "%"MAX_SYMLEN_MINUS_1_STR"[^,],0x%x", symbol, &offs) == 2) {
            symcache_symbol_add(modname, symtable, symbol, offs);
        } else if (symbol[0] != '\0' && sscanf(line, ",0x%x", &offs) == 1) {
            /* duplicate entries are allowed to not list the symbol, to save
             * space in the file (mainly for post-call caching i#669)
             */
            symcache_symbol_add(modname, symtable, symbol, offs);
        } else {
            WARN("WARNING: malformed symbol cache line \"%.*s\"\n",
                 next_line - line - 1, line);
            /* We abort in case there were two dueling writes to the file
             * and it somehow got past the self-consistency check,
             * putting a header in the middle of the file, and we can't
             * trust subsequent lines since they may belong to a different
             * version of the module
             */
            break; /* res should still be true */
        }
    }
    res = true;
 symcache_read_symfile_done:
    if (map != NULL)
        dr_unmap_file(map, actual_size);
    if (f != INVALID_FILE)
        dr_close_file(f);
    return res;
}