Skip to content

Commit 08c1fa7

Browse files
Relay correct source paths in DWARF debug info (#2303)
## Motivation for the change, related issues It is possible to build php-wasm with DWARF debug info today, but actually using the debugger to step through source lines requires additional configuration to map original source file paths (from Docker) to actual source file paths in the host OS. The purpose of this PR is to set the correct source paths at build time so folks can debug php-wasm without additional configuration. This is not just a matter of convenience. Some debuggers (VSCode) only allow a single path mapping, so we cannot step into source files from different directory subtrees at the same time (for example, php-src and php_wasm.c). It would be simpler, faster, and more complete for debugging with DWARF to work out of the box. ## Implementation details This PR adds compilation flags like the following to establish compilation dir and source file paths relative to that: - `-fdebug-compilation-dir=${OUTPUT_DIR_FOR_SOURCE_MAP_BASE}/${PHP_VERSION_ESCAPED}/` - `-fdebug-prefix-map=/root/php_wasm.c=${DEBUG_OFFSET_TO_PHP_WASM_PACKAGE}/compile/php/php_wasm.c` ## Testing Instructions (or ideally a Blueprint) ### For php-wasm/node - Build a version of PHP for php-wasm/node - Set a breakpoint at the beginning of `run_cli()` in `php_wasm.c` - Run the "Debug PHP-WASM CLI with DWARF Symbols" target in VSCode - Select the version of PHP built with debug info - Observe you hit the breakpoint - Step through execution and into a php-src file to demonstrate that mapping works ### For php-wasm/web - Build a version of PHP for php-wasm/web - Run `npm run dev` - Launch Chrome Canary - Install the [C/C++ DevTools Support (DWARF) extension](https://chromewebstore.google.com/detail/cc++-devtools-support-dwa/pdcpmagijalfljmkmjngeonclgbbannb) if you don't already have it - Navigate to http://127.0.0.1:5400/website-server/ - Select the version of PHP built with debug info - Open the devtools Sources tab - Try to open `php_wasm.c`. If the file shows up, it indicates there are DWARF mappings to that file. - Try to open `zend_alloc.c`. If the file shows up, it indicates the DWARF mappings to PHP source files are working. - Set a breakpoint at an interesting place and try to hit it.
1 parent 776070d commit 08c1fa7

File tree

5 files changed

+92
-11
lines changed

5 files changed

+92
-11
lines changed

.vscode/launch.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,23 @@
6464
"cwd": "${workspaceFolder}",
6565
"autoAttachChildProcesses": true
6666
},
67+
{
68+
"name": "Debug Playground CLI with DWARF Symbols",
69+
"request": "launch",
70+
"type": "node",
71+
"runtimeVersion": "23",
72+
"runtimeExecutable": "npx",
73+
"runtimeArgs": [
74+
"nx",
75+
"debug",
76+
"playground-cli",
77+
"server",
78+
],
79+
"args": "${input:playgroundCliCommand}",
80+
"cwd": "${workspaceFolder}",
81+
"autoAttachChildProcesses": true,
82+
"enableDWARF": true
83+
},
6784
{
6885
"name": "Launch Chrome",
6986
"request": "launch",

packages/php-wasm/compile/Makefile

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
2+
MAKEFILE_DIR := $(dir $(MAKEFILE_PATH))
3+
4+
# Remove trailing slash if present
5+
MAKEFILE_DIR := $(patsubst %/,%,$(MAKEFILE_DIR))
6+
17
base-image: base-image/.ready
28
base-image/.ready:
39
cd base-image; docker build -f ./Dockerfile -t playground-php-wasm:base .
@@ -142,19 +148,34 @@ libopenssl/jspi/dist/1.1.1/root/lib/lib/libssl.a: base-image libz_jspi
142148
docker cp $$(docker create playground-php-wasm:libopenssl-1.1.1):/root/install/lib ./libopenssl/jspi/dist/1.1.1/root/lib
143149
docker cp $$(docker create playground-php-wasm:libopenssl-1.1.1):/root/install/include ./libopenssl/jspi/dist/1.1.1/root/lib
144150

151+
WITH_DEBUG ?= no
152+
145153
libsqlite3_asyncify: libsqlite3/asyncify/dist/root/lib/lib/libsqlite3.a
146154
libsqlite3/asyncify/dist/root/lib/lib/libsqlite3.a: base-image libz_asyncify
147155
mkdir -p ./libsqlite3/asyncify/dist/root/lib
148-
docker build -f ./libsqlite3/Dockerfile -t playground-php-wasm:libsqlite3 .
156+
docker build -f ./libsqlite3/Dockerfile -t playground-php-wasm:libsqlite3 . \
157+
--build-arg WITH_DEBUG=${WITH_DEBUG} \
158+
--build-arg DEBUG_DWARF_COMPILATION_DIR=${MAKEFILE_DIR}/libsqlite3
159+
--progress=plain
149160
docker cp $$(docker create playground-php-wasm:libsqlite3):/root/lib/lib ./libsqlite3/asyncify/dist/root/lib
150161
docker cp $$(docker create playground-php-wasm:libsqlite3):/root/lib/include ./libsqlite3/asyncify/dist/root/lib
162+
@if [ "${WITH_DEBUG}" = "yes" ]; then \
163+
docker cp $$(docker create playground-php-wasm:libsqlite3):/root/sqlite-src ./libsqlite3/; \
164+
fi
151165

152166
libsqlite3_jspi: libsqlite3/jspi/dist/root/lib/lib/libsqlite3.a
153167
libsqlite3/jspi/dist/root/lib/lib/libsqlite3.a: base-image libz_jspi
154168
mkdir -p ./libsqlite3/jspi/dist/root/lib
155-
docker build -f ./libsqlite3/Dockerfile -t playground-php-wasm:libsqlite3 . --build-arg JSPI=1
169+
docker build -f ./libsqlite3/Dockerfile -t playground-php-wasm:libsqlite3 . \
170+
--build-arg JSPI=1 \
171+
--build-arg WITH_DEBUG=${WITH_DEBUG} \
172+
--build-arg DEBUG_DWARF_COMPILATION_DIR=${MAKEFILE_DIR}/libsqlite3
173+
--progress=plain
156174
docker cp $$(docker create playground-php-wasm:libsqlite3):/root/lib/lib ./libsqlite3/jspi/dist/root/lib
157175
docker cp $$(docker create playground-php-wasm:libsqlite3):/root/lib/include ./libsqlite3/jspi/dist/root/lib
176+
@if [ "${WITH_DEBUG}" = "yes" ]; then \
177+
docker cp $$(docker create playground-php-wasm:libsqlite3):/root/sqlite-src ./libsqlite3/; \
178+
fi
158179

159180
libiconv_asyncify: libiconv/asyncify/dist/root/lib/lib/libiconv.a
160181
libiconv/asyncify/dist/root/lib/lib/libiconv.a: base-image libz_asyncify

packages/php-wasm/compile/build.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,9 +239,18 @@ await asyncSpawn(
239239
'--build-arg',
240240
getArg('WITH_SOURCEMAPS'),
241241
'--build-arg',
242-
`OUTPUT_DIR_FOR_SOURCE_MAP_BASE=${outputDir}`,
242+
// Relay output directory so we can create source maps and DWARF debug
243+
// info containing correct paths.
244+
`OUTPUT_DIR_ON_HOST=${outputDir}`,
243245
'--build-arg',
244246
getArg('WITH_DEBUG'),
247+
// This directory path allows us to set what the DWARF file references
248+
// are relative to so step debugging source files works correctly.
249+
'--build-arg',
250+
`DEBUG_DWARF_COMPILATION_DIR=${path.resolve(
251+
import.meta.dirname,
252+
'..'
253+
)}`,
245254
'--build-arg',
246255
getArg('WITH_ICONV'),
247256
'--build-arg',

packages/php-wasm/compile/libsqlite3/Dockerfile

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
FROM playground-php-wasm:base
22

33
ARG JSPI
4+
ARG WITH_DEBUG
5+
ARG DEBUG_DWARF_COMPILATION_DIR
46

57
RUN mkdir -p /root/lib/include /root/lib/lib
68
COPY ./libz/ /root/libz
@@ -15,13 +17,26 @@ RUN if [ "$JSPI" = "1" ]; then \
1517
RUN set -euxo pipefail &&\
1618
wget --no-check-certificate https://www.sqlite.org/2022/sqlite-autoconf-3400100.tar.gz && \
1719
tar -xzvf sqlite-autoconf-3400100.tar.gz && \
18-
cd sqlite-autoconf-3400100 && \
20+
mv sqlite-autoconf-3400100 sqlite-src && \
21+
cd sqlite-src && \
1922
source /root/emsdk/emsdk_env.sh && \
2023
emconfigure ./configure \
2124
--build i386-pc-linux-gnu \
2225
--target wasm32-unknown-emscripten \
2326
--prefix=/root/lib/ && \
2427
export JSPI_FLAGS=$(if [ "$JSPI" = "1" ]; then echo "-sSUPPORT_LONGJMP=wasm -fwasm-exceptions"; else echo ""; fi) && \
25-
EMCC_SKIP="-lc" EMCC_FLAGS=" -D__x86_64__ -sSIDE_MODULE $JSPI_FLAGS" emmake make && \
28+
export EMCC_SKIP="-lc"; \
29+
export EMCC_FLAGS=" \
30+
-D__x86_64__ -sSIDE_MODULE \
31+
$JSPI_FLAGS \
32+
$(\
33+
if [ "$WITH_DEBUG" = "yes" ]; then \
34+
echo "-g3 -fdebug-compilation-dir=${DEBUG_DWARF_COMPILATION_DIR}/sqlite-src "; \
35+
else \
36+
echo ''; \
37+
fi \
38+
)\
39+
"; \
40+
emmake make && \
2641
emmake make install
2742

packages/php-wasm/compile/php/Dockerfile

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,9 @@ ARG WITH_MYSQL
8888
ARG WITH_OPENSSL
8989
ARG WITH_ICONV
9090
ARG WITH_SOURCEMAPS
91-
ARG OUTPUT_DIR_FOR_SOURCE_MAP_BASE
91+
ARG OUTPUT_DIR_ON_HOST
9292
ARG WITH_DEBUG
93+
ARG DEBUG_DWARF_COMPILATION_DIR
9394
ARG WITH_WS_NETWORKING_PROXY
9495
ARG WITH_INTL
9596

@@ -160,7 +161,10 @@ RUN if [ "$WITH_CLI_SAPI" = "yes" ]; \
160161
then \
161162
# Configure build flags
162163
echo -n ' --enable-phar --enable-cli=static ' >> /root/.php-configure-flags && \
163-
echo -n ' sapi/cli/php_cli_process_title.c sapi/cli/ps_title.c sapi/cli/php_http_parser.c sapi/cli/php_cli_server.c sapi/cli/php_cli.c ' \
164+
echo -n ' /root/php-src/sapi/cli/php_cli_process_title.c /root/php-src/sapi/cli/ps_title.c ' \
165+
# Use absolute paths to help path mapping for DWARF debug info
166+
'/root/php-src/sapi/cli/php_http_parser.c /root/php-src/sapi/cli/php_cli_server.c ' \
167+
'/root/php-src/sapi/cli/php_cli.c ' \
164168
>> /root/.emcc-php-wasm-sources && \
165169
echo -n ', "_run_cli", "_wasm_add_cli_arg"' >> /root/.EXPORTED_FUNCTIONS && \
166170
echo -n ' -DWITH_CLI_SAPI=1 ' >> /root/.emcc-php-wasm-flags && \
@@ -471,10 +475,16 @@ EOF
471475
RUN echo '' > /root/php-src/ext/standard/proc_open.h;
472476
RUN echo '' > /root/php-src/ext/standard/proc_open.c;
473477

478+
ARG OUTPUT_DIR_ON_HOST
479+
ARG DEBUG_DWARF_COMPILATION_DIR
474480
RUN source /root/emsdk/emsdk_env.sh && \
475481
# We're compiling PHP as emscripten's side module...
476482
export JSPI_FLAGS=$(if [ "$WITH_JSPI" = "yes" ]; then echo "-sSUPPORT_LONGJMP=wasm -fwasm-exceptions"; else echo ""; fi) && \
477-
EMCC_FLAGS=" -D__x86_64__ -sSIDE_MODULE -Dsetsockopt=wasm_setsockopt -Dphp_exec=wasm_php_exec $JSPI_FLAGS " \
483+
export PHP_VERSION_ESCAPED="${PHP_VERSION//./_}" && \
484+
EMCC_FLAGS=" -D__x86_64__ -sSIDE_MODULE -Dsetsockopt=wasm_setsockopt -Dphp_exec=wasm_php_exec \
485+
$JSPI_FLAGS \
486+
-fdebug-compilation-dir=${DEBUG_DWARF_COMPILATION_DIR}/ \
487+
-fdebug-prefix-map=/root/php-src/=${OUTPUT_DIR_ON_HOST}/${PHP_VERSION_ESCAPED}/php-src/ " \
478488
# ...which means we must skip all the libraries - they will be provided in the final linking step.
479489
EMCC_SKIP="-lz -ledit -ldl -lncurses -lzip -lpng16 -lssl -lcrypto -licuuc -licudata -licui18n -licuio -lxml2 -lc -lm -lsqlite3 /root/lib/lib/libxml2.a /root/lib/lib/libsqlite3.so /root/lib/lib/libsqlite3.a /root/lib/lib/libsqlite3.a /root/lib/lib/libpng16.so /root/lib/lib/libwebp.a /root/lib/lib/libsharpyuv.a /root/lib/lib/libjpeg.a" \
480490
emmake make -j1
@@ -494,7 +504,8 @@ RUN if [[ "${PHP_VERSION:0:1}" -le "7" && "${PHP_VERSION:2:1}" -le "3" ]]; then
494504
fi
495505

496506
ARG WITH_SOURCEMAPS
497-
ARG OUTPUT_DIR_FOR_SOURCE_MAP_BASE
507+
ARG OUTPUT_DIR_ON_HOST
508+
ARG DEBUG_DWARF_COMPILATION_DIR
498509
ARG WITH_DEBUG
499510
RUN set -euxo pipefail; \
500511
if [ "$EMSCRIPTEN_ENVIRONMENT" = "node" ]; then \
@@ -503,13 +514,20 @@ RUN set -euxo pipefail; \
503514
fi; \
504515
if [ "${WITH_SOURCEMAPS}" = "yes" ] || [ "${WITH_DEBUG}" = "yes" ]; then \
505516
echo -n ' -g3 ' >> /root/.emcc-php-wasm-flags; \
517+
# Make source file paths relative to the location of the .wasm file
518+
# so we can debug without additional config in host OS.
519+
export PHP_VERSION_ESCAPED="${PHP_VERSION//./_}"; \
520+
echo -n " -fdebug-compilation-dir=${DEBUG_DWARF_COMPILATION_DIR}/ " \
521+
"-fdebug-prefix-map=/root/php_wasm.c=${DEBUG_DWARF_COMPILATION_DIR}/compile/php/php_wasm.c " \
522+
"-fdebug-prefix-map=/root/php-src/=${OUTPUT_DIR_ON_HOST}/${PHP_VERSION_ESCAPED}/php-src/ " \
523+
"-fdebug-prefix-map=./=${OUTPUT_DIR_ON_HOST}/${PHP_VERSION_ESCAPED}/php-src/ " \
524+
>> /root/.emcc-php-wasm-flags; \
506525
if [ "${WITH_SOURCEMAPS}" = "yes" ]; then \
507526
echo -n ' -gsource-map' >> /root/.emcc-php-wasm-flags; \
508527
# Ensure source maps are loaded from the correct URL on the web.
509528
# Without this, browsers will try the wasm:// protocol and never load the source map.
510529
if [ "$EMSCRIPTEN_ENVIRONMENT" = "web" ]; then \
511-
export PHP_VERSION_ESCAPED="${PHP_VERSION//./_}"; \
512-
echo -n " --source-map-base http://127.0.0.1:5400/@fs${OUTPUT_DIR_FOR_SOURCE_MAP_BASE}/${PHP_VERSION_ESCAPED}/" >> /root/.emcc-php-wasm-flags; \
530+
echo -n " --source-map-base http://127.0.0.1:5400/@fs${OUTPUT_DIR_ON_HOST}/${PHP_VERSION_ESCAPED}/" >> /root/.emcc-php-wasm-flags; \
513531
fi; \
514532
fi; \
515533
else \
@@ -2069,6 +2087,7 @@ RUN set -euxo pipefail; \
20692087
-s MIN_NODE_VERSION=200900 \
20702088
-s INITIAL_MEMORY=1024MB \
20712089
-s ALLOW_MEMORY_GROWTH=1 \
2090+
-s ASSERTIONS=0 \
20722091
-s ERROR_ON_UNDEFINED_SYMBOLS=1 \
20732092
-s NODEJS_CATCH_EXIT=0 \
20742093
-s NODEJS_CATCH_REJECTION=0 \

0 commit comments

Comments
 (0)