in agent/native/ext/AST_instrumentation.cpp [581:668]
ResultCode insertAstForFunctionPreHook( zend_ast_decl* funcAstDecl, ArgCaptureSpecArrayView argCaptureSpecs )
{
// Before:
//
// function add_filter( $hook_name, $callback, $priority = 10, $accepted_args = 1 ) {
// ////////////////////////////
// // original function body //
// ////////////////////////////
// }
//
// ZEND_AST_FUNC_DECL (name: add_filter, line: 7, flags: 0, attr: 0, childCount: 4)
// ZEND_AST_PARAM_LIST (line: 7, attr: 0, childCount: 4)
// NULL
// ZEND_AST_STMT_LIST (line: 7, attr: 0, childCount: 4) <- original function body
// NULL
//
// After:
//
// function add_filter( $hook_name, $callback, $priority = 10, $accepted_args = 1 ) { /* fold-into-one-line-begin */
// \elastic_apm_ast_instrumentation_pre_hook( /* pre-hook args */ );
// { /* fold-into-one-line-end */
// ////////////////////////////
// // original function body //
// ////////////////////////////
// } }
//
// ZEND_AST_FUNC_DECL (name: add_filter, line: 24, flags: 0, attr: 0, childCount: 4)
// ZEND_AST_PARAM_LIST (line: 24, attr: 0, childCount: 4)
// NULL
// ZEND_AST_STMT_LIST (line: 24, attr: 0, childCount: 2) <- new function body
// ZEND_AST_CALL (line: 24, attr: 0, childCount: 2)
// ZEND_AST_ZVAL (line: 24, attr: 0) [type: string, value: elastic_apm_ast_instrumentation_pre_hook]
// ZEND_AST_ARG_LIST (line: 24, attr: 0, childCount: 3) <- pre-hook args
// ZEND_AST_STMT_LIST (line: 24, attr: 0, childCount: 4) <- original function body
// NULL
ELASTIC_APM_ASSERT_VALID_PTR( funcAstDecl );
ResultCode resultCode;
char txtOutStreamBuf[ELASTIC_APM_TEXT_OUTPUT_STREAM_ON_STACK_BUFFER_SIZE];
TextOutputStream txtOutStream = ELASTIC_APM_TEXT_OUTPUT_STREAM_FROM_STATIC_BUFFER( txtOutStreamBuf );
String dbgCompiledFileName = stringIfNotNullElse( nullableZStringToStringView( CG(compiled_filename) ).begin, "<N/A>" );
ELASTIC_APM_ASSERT( funcAstDecl->kind == ZEND_AST_FUNC_DECL || funcAstDecl->kind == ZEND_AST_METHOD, "funcAstDecl->kind: %s", streamZendAstKind( funcAstDecl->kind, &txtOutStream ) );
textOutputStreamRewind( &txtOutStream );
zend_ast* originalFuncBodyAst = nullptr;
zend_ast* preHookCallAstArgList = nullptr;
StringView dbgFuncName;
if ( ! getAstDeclName( funcAstDecl, /* out */ &dbgFuncName ) )
{
ELASTIC_APM_LOG_ERROR( "Failed to get function name - returning failure" );
ELASTIC_APM_SET_RESULT_CODE_AND_GOTO_FAILURE();
}
ELASTIC_APM_LOG_DEBUG_FUNCTION_ENTRY_MSG( "dbgFuncName: %s, compiled_filename: %s", dbgFuncName.begin, dbgCompiledFileName );
debugDumpAstTreeToLog( (zend_ast*) funcAstDecl, logLevel_debug );
originalFuncBodyAst = funcAstDecl->child[ g_funcDeclBodyChildIndex ];
if ( originalFuncBodyAst == NULL )
{
ELASTIC_APM_LOG_TRACE( "originalFuncBodyAst == NULL" );
ELASTIC_APM_SET_RESULT_CODE_AND_GOTO_FAILURE();
}
if ( originalFuncBodyAst->kind != ZEND_AST_STMT_LIST )
{
ELASTIC_APM_LOG_TRACE( "Expected originalFuncBodyAst->kind to be ZEND_AST_STMT_LIST but it is %s", streamZendAstKind( originalFuncBodyAst->kind, &txtOutStream ) );
textOutputStreamRewind( &txtOutStream );
ELASTIC_APM_SET_RESULT_CODE_AND_GOTO_FAILURE();
}
ELASTIC_APM_CALL_IF_FAILED_GOTO( createPreHookAstArgListByCaptureSpec( funcAstDecl, argCaptureSpecs, /* out */ &preHookCallAstArgList ) );
funcAstDecl->child[ g_funcDeclBodyChildIndex ] = createAstListWithTwoChildren(
ZEND_AST_STMT_LIST
, createAstStandaloneFqFunctionCall( g_elastic_apm_ast_instrumentation_pre_hook_funcName, preHookCallAstArgList )
, originalFuncBodyAst
);
resultCode = resultSuccess;
finally:
ELASTIC_APM_LOG_DEBUG_RESULT_CODE_FUNCTION_EXIT_MSG();
debugDumpAstTreeToLog( (zend_ast*) funcAstDecl, logLevel_debug );
return resultCode;
failure:
goto finally;
}