Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions .github/workflows/dump_structs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
name: dump_structs

# One-off, manually-triggered probe: builds php-src from source for every PHP
# version phpspy ships struct mirrors for, on both x86_64 and aarch64, and
# uploads the raw struct_dump.gdb output as build artifacts. This is how real
# (not guessed) aarch64 offsets get produced -- see struct_dump.sh/.gdb and
# CLAUDE.md. Not run on push/pull_request: 12 versions x 2 arches, each a full
# ./buildconf && ./configure && make, is far too slow for routine CI.

on:
workflow_dispatch:

jobs:
dump:
strategy:
fail-fast: false
matrix:
runs_on: [ubuntu-24.04, ubuntu-24.04-arm]
phpv:
- php-7.0.33
- php-7.1.33
- php-7.2.34
- php-7.3.33
- php-7.4.33
- php-8.0.30
- php-8.1.28
- php-8.2.18
- php-8.3.6
- php-8.4.25
- php-8.5.10
- master

runs-on: ${{ matrix.runs_on }}

steps:
- name: checkout phpspy
uses: actions/checkout@v4
with:
path: phpspy

- name: checkout php-src
uses: actions/checkout@v4
with:
repository: php/php-src
path: php-src
fetch-depth: 0

- name: deps
run: |
sudo apt-get update
sudo apt-get install -y \
autoconf bison re2c pkg-config build-essential gdb \
libxml2-dev libsqlite3-dev libssl-dev

- name: dump
run: ./phpspy/struct_dump.sh "$GITHUB_WORKSPACE/php-src" "${{ matrix.phpv }}"

- name: upload
uses: actions/upload-artifact@v4
with:
name: struct_dump-${{ matrix.runs_on }}-${{ matrix.phpv }}
path: phpspy/struct_dump.${{ matrix.phpv }}.out
if-no-files-found: warn
7 changes: 5 additions & 2 deletions phpspy_trace.c
Original file line number Diff line number Diff line change
Expand Up @@ -340,8 +340,11 @@ static int trace_locals(trace_context *context, zend_op *zop, zend_execute_data
HASH_FIND(hh, entry->varmap, tmp, tmp_len, var);
if (!var) continue;
num_vars_found += 1;
/* See ZEND_CALL_VAR_NUM macro in php-src */
try_copy_proc_mem("zval", ((zval*)(remote_execute_data)) + ((int)(5 + i)), &zv, sizeof(zv));
/* See ZEND_CALL_VAR_NUM macro in php-src. The frame-slot count is
version-dependent (PHP 7.0 differs from every later version); see
phpspy_frame_slot, defined per-phpv in phpspy_trace_tpl.c and for
USE_ZEND in structs/structs.h. */
try_copy_proc_mem("zval", ((zval*)(remote_execute_data)) + ((int)(phpspy_frame_slot + i)), &zv, sizeof(zv));
try(rv, sprint_zval(context, &zv, tmp, sizeof(tmp), &tmp_len));
context->event.varpeek.entry = entry;
context->event.varpeek.var = var;
Expand Down
12 changes: 12 additions & 0 deletions phpspy_trace_tpl.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,17 @@
#define sprint_pdo_binds concat2(sprint_pdo_binds_, phpv)
#define sprint_pdo_bind concat2(sprint_pdo_bind_, phpv)

/* ZEND_CALL_FRAME_SLOT = ceil(sizeof(zend_execute_data) / sizeof(zval)). Measured
directly against every supported PHP version's real headers: 6 on 7.0 (which
still carries execute_data.called_scope, removed in 7.1), 5 on every later
version (sizeof(zend_execute_data) is 72 or 80 there, both of which round up
to 5 slots of 16 bytes). */
#if phpv == 70
#define phpspy_frame_slot 6
#else
#define phpspy_frame_slot 5
#endif

#include "phpspy_trace.c"

#undef concat1
Expand Down Expand Up @@ -73,6 +84,7 @@
#undef trace_pdo
#undef sprint_pdo_binds
#undef sprint_pdo_bind
#undef phpspy_frame_slot
#undef copy_executor_globals
#undef copy_zarray_bucket
#undef sprint_zstring
Expand Down
7 changes: 7 additions & 0 deletions struct_dump.gdb
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,13 @@ whatis zval
fieldof zval u2.next
printf "\n"

# Cross-check for phpspy_frame_slot (phpspy_trace_tpl.c / structs/structs.h):
# ZEND_CALL_FRAME_SLOT = ceil(sizeof(zend_execute_data) / sizeof(zval)).
printf "frame_slot\n"
printf " sizeof(zend_execute_data) %lu\n", sizeof(zend_execute_data)
printf " sizeof(zval) %lu\n", sizeof(zval)
printf "\n"

printf "Bucket\n"
whatis Bucket
fieldof Bucket val
Expand Down
38 changes: 27 additions & 11 deletions struct_dump.sh
Original file line number Diff line number Diff line change
@@ -1,28 +1,44 @@
#!/bin/bash
this_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null && pwd)
phpsrc_dir=$1
only_phpv=$2

if [ -z "$phpsrc_dir" ]; then
echo "Required: php-src directory"
exit 1
fi

# All PHP versions phpspy ships struct mirrors for. 8.6 has no release tag yet
# (still dev), so it stays pinned to `master`, same as when the 8.6 structs
# were first cut.
all_phpvs=(
php-7.0.33
php-7.1.33
php-7.2.34
php-7.3.33
php-7.4.33
php-8.0.30
php-8.1.28
php-8.2.18
php-8.3.6
php-8.4.25
php-8.5.10
master
)

if [ -n "$only_phpv" ]; then
phpvs=("$only_phpv")
else
phpvs=("${all_phpvs[@]}")
fi

pushd "$phpsrc_dir" || exit 1
git fetch --tags
for phpv in php-7.0.33 \
php-7.1.33 \
php-7.2.34 \
php-7.3.33 \
php-7.4.33 \
php-8.0.30 \
php-8.1.28 \
php-8.2.18 \
php-8.3.6 \
master
for phpv in "${phpvs[@]}"
do
git reset --hard HEAD \
&& git clean -fdx \
&& git checkout $phpv \
&& git checkout "$phpv" \
&& git clean -fdx \
&& ./buildconf --force \
&& ./configure \
Expand Down
7 changes: 2 additions & 5 deletions structs/aarch64/php_structs_70.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
#ifndef __php_structs_70_h
#define __php_structs_70_h

/* TODO: These structs are wrong for aarch64 */

#include <stdint.h>

typedef struct _zend_executor_globals_70 zend_executor_globals_70;
Expand Down Expand Up @@ -122,8 +120,8 @@ struct __attribute__((__packed__)) _sapi_request_info_70 {
struct __attribute__((__packed__)) _sapi_globals_struct_70 {
uint8_t pad0[8]; /* 0 +8 */
sapi_request_info_70 request_info; /* 8 +48 */
uint8_t pad1[384]; /* 56 +384 */
double global_request_time; /* 440 +8 */
uint8_t pad1[368]; /* 56 +368 */
double global_request_time; /* 424 +8 */
};

struct __attribute__((__packed__)) _Bucket_70 {
Expand All @@ -142,7 +140,6 @@ struct __attribute__((__packed__)) _zend_mm_heap_70 {
size_t peak; /* 24 +8 */
};


struct __attribute__((__packed__)) _zend_object_70 {
uint8_t pad0[16]; /* 0 +16 */
zend_class_entry_70 *ce; /* 16 +8 */
Expand Down
7 changes: 2 additions & 5 deletions structs/aarch64/php_structs_71.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
#ifndef __php_structs_71_h
#define __php_structs_71_h

/* TODO: These structs are wrong for aarch64 */

#include <stdint.h>

typedef struct _zend_executor_globals_71 zend_executor_globals_71;
Expand Down Expand Up @@ -121,8 +119,8 @@ struct __attribute__((__packed__)) _sapi_request_info_71 {
struct __attribute__((__packed__)) _sapi_globals_struct_71 {
uint8_t pad0[8]; /* 0 +8 */
sapi_request_info_71 request_info; /* 8 +48 */
uint8_t pad1[384]; /* 56 +384 */
double global_request_time; /* 440 +8 */
uint8_t pad1[368]; /* 56 +368 */
double global_request_time; /* 424 +8 */
};

struct __attribute__((__packed__)) _Bucket_71 {
Expand All @@ -141,7 +139,6 @@ struct __attribute__((__packed__)) _zend_mm_heap_71 {
size_t peak; /* 24 +8 */
};


struct __attribute__((__packed__)) _zend_object_71 {
uint8_t pad0[16]; /* 0 +16 */
zend_class_entry_71 *ce; /* 16 +8 */
Expand Down
7 changes: 2 additions & 5 deletions structs/aarch64/php_structs_72.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
#ifndef __php_structs_72_h
#define __php_structs_72_h

/* TODO: These structs are wrong for aarch64 */

#include <stdint.h>

typedef struct _zend_executor_globals_72 zend_executor_globals_72;
Expand Down Expand Up @@ -121,8 +119,8 @@ struct __attribute__((__packed__)) _sapi_request_info_72 {
struct __attribute__((__packed__)) _sapi_globals_struct_72 {
uint8_t pad0[8]; /* 0 +8 */
sapi_request_info_72 request_info; /* 8 +48 */
uint8_t pad1[384]; /* 56 +384 */
double global_request_time; /* 440 +8 */
uint8_t pad1[368]; /* 56 +368 */
double global_request_time; /* 424 +8 */
};

struct __attribute__((__packed__)) _Bucket_72 {
Expand All @@ -141,7 +139,6 @@ struct __attribute__((__packed__)) _zend_mm_heap_72 {
size_t peak; /* 24 +8 */
};


struct __attribute__((__packed__)) _zend_object_72 {
uint8_t pad0[16]; /* 0 +16 */
zend_class_entry_72 *ce; /* 16 +8 */
Expand Down
7 changes: 2 additions & 5 deletions structs/aarch64/php_structs_73.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
#ifndef __php_structs_73_h
#define __php_structs_73_h

/* TODO: These structs are wrong for aarch64 */

#include <stdint.h>

typedef struct _zend_executor_globals_73 zend_executor_globals_73;
Expand Down Expand Up @@ -121,8 +119,8 @@ struct __attribute__((__packed__)) _sapi_request_info_73 {
struct __attribute__((__packed__)) _sapi_globals_struct_73 {
uint8_t pad0[8]; /* 0 +8 */
sapi_request_info_73 request_info; /* 8 +48 */
uint8_t pad1[384]; /* 56 +384 */
double global_request_time; /* 440 +8 */
uint8_t pad1[368]; /* 56 +368 */
double global_request_time; /* 424 +8 */
};

struct __attribute__((__packed__)) _Bucket_73 {
Expand All @@ -141,7 +139,6 @@ struct __attribute__((__packed__)) _zend_mm_heap_73 {
size_t peak; /* 24 +8 */
};


struct __attribute__((__packed__)) _zend_object_73 {
uint8_t pad0[16]; /* 0 +16 */
zend_class_entry_73 *ce; /* 16 +8 */
Expand Down
7 changes: 2 additions & 5 deletions structs/aarch64/php_structs_74.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
#ifndef __php_structs_74_h
#define __php_structs_74_h

/* TODO: These structs are wrong for aarch64 */

#include <stdint.h>

typedef struct _zend_executor_globals_74 zend_executor_globals_74;
Expand Down Expand Up @@ -121,8 +119,8 @@ struct __attribute__((__packed__)) _sapi_request_info_74 {
struct __attribute__((__packed__)) _sapi_globals_struct_74 {
uint8_t pad0[8]; /* 0 +8 */
sapi_request_info_74 request_info; /* 8 +48 */
uint8_t pad1[384]; /* 56 +384 */
double global_request_time; /* 440 +8 */
uint8_t pad1[368]; /* 56 +368 */
double global_request_time; /* 424 +8 */
};

struct __attribute__((__packed__)) _Bucket_74 {
Expand All @@ -141,7 +139,6 @@ struct __attribute__((__packed__)) _zend_mm_heap_74 {
size_t peak; /* 24 +8 */
};


struct __attribute__((__packed__)) _zend_object_74 {
uint8_t pad0[16]; /* 0 +16 */
zend_class_entry_74 *ce; /* 16 +8 */
Expand Down
7 changes: 2 additions & 5 deletions structs/aarch64/php_structs_80.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
#ifndef __php_structs_80_h
#define __php_structs_80_h

/* TODO: These structs are wrong for aarch64 */

#include <stdint.h>

typedef struct _zend_executor_globals_80 zend_executor_globals_80;
Expand Down Expand Up @@ -121,8 +119,8 @@ struct __attribute__((__packed__)) _sapi_request_info_80 {
struct __attribute__((__packed__)) _sapi_globals_struct_80 {
uint8_t pad0[8]; /* 0 +8 */
sapi_request_info_80 request_info; /* 8 +48 */
uint8_t pad1[384]; /* 56 +384 */
double global_request_time; /* 440 +8 */
uint8_t pad1[368]; /* 56 +368 */
double global_request_time; /* 424 +8 */
};

struct __attribute__((__packed__)) _Bucket_80 {
Expand All @@ -141,7 +139,6 @@ struct __attribute__((__packed__)) _zend_mm_heap_80 {
size_t peak; /* 24 +8 */
};


struct __attribute__((__packed__)) _zend_object_80 {
uint8_t pad0[16]; /* 0 +16 */
zend_class_entry_80 *ce; /* 16 +8 */
Expand Down
7 changes: 2 additions & 5 deletions structs/aarch64/php_structs_81.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
#ifndef __php_structs_81_h
#define __php_structs_81_h

/* TODO: These structs are wrong for aarch64 */

#include <stdint.h>

typedef struct _zend_executor_globals_81 zend_executor_globals_81;
Expand Down Expand Up @@ -121,8 +119,8 @@ struct __attribute__((__packed__)) _sapi_request_info_81 {
struct __attribute__((__packed__)) _sapi_globals_struct_81 {
uint8_t pad0[8]; /* 0 +8 */
sapi_request_info_81 request_info; /* 8 +48 */
uint8_t pad1[384]; /* 56 +384 */
double global_request_time; /* 440 +8 */
uint8_t pad1[368]; /* 56 +368 */
double global_request_time; /* 424 +8 */
};

struct __attribute__((__packed__)) _Bucket_81 {
Expand All @@ -141,7 +139,6 @@ struct __attribute__((__packed__)) _zend_mm_heap_81 {
size_t peak; /* 24 +8 */
};


struct __attribute__((__packed__)) _zend_object_81 {
uint8_t pad0[16]; /* 0 +16 */
zend_class_entry_81 *ce; /* 16 +8 */
Expand Down
7 changes: 2 additions & 5 deletions structs/aarch64/php_structs_82.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
#ifndef __php_structs_82_h
#define __php_structs_82_h

/* TODO: These structs are wrong for aarch64 */

#include <stdint.h>

typedef struct _zend_executor_globals_82 zend_executor_globals_82;
Expand Down Expand Up @@ -121,8 +119,8 @@ struct __attribute__((__packed__)) _sapi_request_info_82 {
struct __attribute__((__packed__)) _sapi_globals_struct_82 {
uint8_t pad0[8]; /* 0 +8 */
sapi_request_info_82 request_info; /* 8 +48 */
uint8_t pad1[384]; /* 56 +384 */
double global_request_time; /* 440 +8 */
uint8_t pad1[368]; /* 56 +368 */
double global_request_time; /* 424 +8 */
};

struct __attribute__((__packed__)) _Bucket_82 {
Expand All @@ -141,7 +139,6 @@ struct __attribute__((__packed__)) _zend_mm_heap_82 {
size_t peak; /* 24 +8 */
};


struct __attribute__((__packed__)) _zend_object_82 {
uint8_t pad0[16]; /* 0 +16 */
zend_class_entry_82 *ce; /* 16 +8 */
Expand Down
Loading
Loading