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
51 changes: 51 additions & 0 deletions .github/workflows/v8dasm-linux-84.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Builds View8's disassembler for V8 8.4.371.22 (NW.js 0.47.2) on Linux.
# Start it by hand: Actions tab -> "v8dasm Linux (V8 8.4)" -> Run workflow.
# Builds two versions side by side (pointer compression on / off).

name: v8dasm Linux (V8 8.4)

on:
workflow_dispatch:

jobs:
build:
name: V8 8.4.371.22 - pointer compression ${{ matrix.pc }}
runs-on: ubuntu-22.04
timeout-minutes: 340
strategy:
fail-fast: false
matrix:
pc: [true, false]
env:
V8_VERSION: 8.4.371.22
PC: ${{ matrix.pc }}

steps:
- uses: actions/checkout@v4

- name: Free disk space
run: |
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc \
/opt/hostedtoolcache/CodeQL /usr/local/share/boost
df -h /

- name: Build v8dasm
run: bash linux84/build.sh

- name: Try View8 on the self-test
continue-on-error: true
run: |
pip install parse
bin=$(ls out/v8dasm-*)
python3 view8.py out/selftest.bin out/selftest.js --path "$bin"
echo "----- decompiled self-test -----"
cat out/selftest.js

- name: Upload
if: always()
uses: actions/upload-artifact@v4
with:
name: v8dasm-8.4.371.22-linux-pc-${{ matrix.pc }}
path: out/
if-no-files-found: ignore
retention-days: 30
6 changes: 3 additions & 3 deletions configs/v8-versions.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"versions": [
{
"v8_version": "14.2.231.21",
"node_version": "Electron 39.2.7 (Chromium 142)",
"build_args": "v8_enable_pointer_compression=true v8_enable_sandbox=true"
"v8_version": "8.4.371.22",
"node_version": "v14.x (NW.js 0.47.2)",
"build_args": "v8_enable_pointer_compression=false"
}
]
}
100 changes: 100 additions & 0 deletions linux84/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#!/usr/bin/env bash
# build.sh build View8's disassembler (v8dasm) for V8 8.4.371.22 on Ubuntu.

set -euo pipefail

V8_VERSION=${V8_VERSION:-8.4.371.22}
PC=${PC:-true}
HERE=$(cd "$(dirname "$0")" && pwd)
OUT=${OUT:-$PWD/out}
WORK=${WORK:-$HOME/v8work}
[ "$PC" = true ] && TAG=on || TAG=off
NAME=v8dasm-$V8_VERSION-pc-$TAG

step() { echo; echo "=====[ $* ]====="; }

step "1/8 System tools"
sudo apt-get update -qq
sudo apt-get install -y -qq python2 ninja-build pkg-config curl git xz-utils lsb-release
# python2 for old v8 2020
sudo ln -sf /usr/bin/python2 /usr/local/bin/python
python --version

step "2/8 depot_tools (Google's download/build helpers)"
mkdir -p "$WORK"
[ -d "$WORK/depot_tools" ] ||
git clone --depth 1 https://chromium.googlesource.com/chromium/tools/depot_tools.git "$WORK/depot_tools"
export PATH="$WORK/depot_tools:$PATH"
gclient --version # first run sets depot_tools up

step "3/8 V8 $V8_VERSION source (only that version, no history)"
cd "$WORK"
if [ ! -d v8/.git ]; then
git init -q v8
git -C v8 remote add origin https://chromium.googlesource.com/v8/v8.git
fi
git -C v8 fetch --depth 1 origin "refs/tags/$V8_VERSION:refs/tags/$V8_VERSION"
# detached hea false doesnt work, so is removed.
git -C v8 log -1 --format='checked out %H (%cd)'

# "managed: False" = gclient leaves our v8 checkout alone and only
# downloads what V8's DEPS file lists (build files, ICU, libc++, ...).
cat > .gclient <<'EOF'
solutions = [{
"name": "v8",
"url": "https://chromium.googlesource.com/v8/v8.git",
"deps_file": "DEPS",
"managed": False,
"custom_deps": {},
}]
EOF
gclient sync --nohooks --no-history -j 8

step "4/8 Compiler + Linux sysroot (the hooks we actually need)"
cd "$WORK/v8"
python build/linux/sysroot_scripts/install-sysroot.py --arch=x64
python tools/clang/scripts/update.py
python build/util/lastchange.py -o build/util/LASTCHANGE || {
echo "lastchange failed - writing a placeholder"
echo "LASTCHANGE=0-0" > build/util/LASTCHANGE
date +%s > build/util/LASTCHANGE.committime
}

step "5/8 Patch V8 so it prints functions"
bash "$HERE/patch-v84.sh" "$WORK/v8"
# replace V8 hello-world sample for V8 build to compile it
cp "$HERE/v8dasm.cpp" samples/hello-world.cc

step "6/8 Configure (pointer compression = $PC)"
ARGS="is_debug=false
is_component_build=false
target_cpu=\"x64\"
v8_enable_pointer_compression=$PC
v8_enable_disassembler=true
v8_enable_object_print=true
v8_use_external_startup_data=false
icu_use_data_file=false
treat_warnings_as_errors=false
symbol_level=0
use_goma=false"
ARGS=$(echo $ARGS)
echo "$ARGS"
buildtools/linux64/gn gen out/dasm --args="$ARGS"

step "7/8 Compile (about an hour)"
/usr/bin/ninja -C out/dasm v8_hello_world
mkdir -p "$OUT"
cp out/dasm/v8_hello_world "$OUT/$NAME"
strip "$OUT/$NAME" || true
ls -lh "$OUT/$NAME"

step "8/8 Self-test"
cd "$OUT"
"./$NAME" --make-test selftest.bin
"./$NAME" selftest.bin > selftest.txt
head -40 selftest.txt
n=$(grep -c '^Start SharedFunctionInfo' selftest.txt || true)
echo "functions printed: $n"
grep -q 'govid' selftest.txt || { echo "SELF-TEST FAILED: no 'govid' in output"; exit 1; }
grep -q '@ 0 : ' selftest.txt || { echo "SELF-TEST FAILED: no bytecode in output"; exit 1; }
echo "SELF-TEST OK"
180 changes: 180 additions & 0 deletions linux84/patch-v84.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
#!/usr/bin/env bash
# patch-v84.sh View8 V8 change, rewrite of V8 8.4.371.22
#
# usage: bash patch-v84.sh /path/to/v8
#
# V8 targets 10+; the script below makes similiar changes but instead finds each spot by text and not ln number.

set -euo pipefail
V8=${1:?give the V8 source folder, e.g. ~/v8work/v8}
cd "$V8"

rep() {
F="$1" OLD="$2" NEW="$3" perl -e '
my ($f, $old, $new) = @ENV{qw(F OLD NEW)};
open my $h, "<", $f or die "cannot read $f\n";
my $s = do { local $/; <$h> }; close $h;
my ($n, $at) = (0, 0);
while (($at = index($s, $old, $at)) >= 0) { $n++; $at += length $old }
if ($n != 1) {
print STDERR "\nPATCH FAILED in $f: expected this text once, found it $n times:\n$old\n";
exit 1;
}
substr($s, index($s, $old), length $old) = $new;
open $h, ">", $f or die "cannot write $f\n"; print $h $s; close $h;
'
echo " ok $1"
}

echo "== 1. src/diagnostics/objects-printer.cc"
F=src/diagnostics/objects-printer.cc

rep $F ' os << Brief(GetCode());
}
PrintSourceCode(os);
' ' os << Brief(GetCode());
}
'

rep $F ' feedback_metadata().FeedbackMetadataPrint(os);
} else {
os << "<none>";
}
os << "\n";
}

void JSGlobalProxy::JSGlobalProxyPrint' ' feedback_metadata().FeedbackMetadataPrint(os);
} else {
os << "<none>";
}
os << "\n";
os << "\nStart BytecodeArray\n";
if (HasBytecodeArray()) {
GetBytecodeArray().Disassemble(os);
} else {
os << "<no bytecode: this function was never compiled>\n";
}
os << "\nEnd BytecodeArray\n";
os << std::flush;
}

void JSGlobalProxy::JSGlobalProxyPrint'

echo "== 2. src/objects/objects.cc"
F=src/objects/objects.cc

rep $F ' case FIXED_ARRAY_TYPE:
os << "<FixedArray[" << FixedArray::cast(*this).length() << "]>";
break;' ' case FIXED_ARRAY_TYPE:
os << "<FixedArray[" << FixedArray::cast(*this).length() << "]>";
os << "\nStart FixedArray\n";
FixedArray::cast(*this).FixedArrayPrint(os);
os << "\nEnd FixedArray\n";
break;'

rep $F ' case OBJECT_BOILERPLATE_DESCRIPTION_TYPE:
os << "<ObjectBoilerplateDescription[" << FixedArray::cast(*this).length()
<< "]>";
break;' ' case OBJECT_BOILERPLATE_DESCRIPTION_TYPE:
os << "<ObjectBoilerplateDescription[" << FixedArray::cast(*this).length()
<< "]>";
os << "\nStart ObjectBoilerplateDescription\n";
ObjectBoilerplateDescription::cast(*this)
.ObjectBoilerplateDescriptionPrint(os);
os << "\nEnd ObjectBoilerplateDescription\n";
break;'

rep $F ' case FIXED_DOUBLE_ARRAY_TYPE:
os << "<FixedDoubleArray[" << FixedDoubleArray::cast(*this).length()
<< "]>";
break;' ' case FIXED_DOUBLE_ARRAY_TYPE:
os << "<FixedDoubleArray[" << FixedDoubleArray::cast(*this).length()
<< "]>";
os << "\nStart FixedDoubleArray\n";
FixedDoubleArray::cast(*this).FixedDoubleArrayPrint(os);
os << "\nEnd FixedDoubleArray\n";
break;'

# Inner functions: print the whole function, not just its name.
rep $F ' os << "<SharedFunctionInfo>";
}
break;
}' ' os << "<SharedFunctionInfo>";
}
os << "\nStart SharedFunctionInfo\n";
shared.SharedFunctionInfoPrint(os);
os << "\nEnd SharedFunctionInfo\n";
break;
}'

echo "== 3. src/objects/string.cc"
F=src/objects/string.cc

rep $F ' int len = length();
if (len > kMaxShortPrintLength) {
accumulator->Add("<Very long string[%s%u]>", internalized_marker, len);
return;
}
' ' int len = length();
'

rep $F ' bool truncated = false;
if (len > kMaxShortPrintLength) {
len = kMaxShortPrintLength;
truncated = true;
}
' ' bool truncated = false;
'

rep $F ' accumulator->Add("<String[%s%u]: ", internalized_marker, length());' \
' accumulator->Add("<String[%u]: %s", length(), internalized_marker);'
rep $F ' accumulator->Add("<String[%s%u]\\: ", internalized_marker, length());' \
' accumulator->Add("<String[%u]\\: %s", length(), internalized_marker);'

echo "== 4. src/snapshot/code-serializer.cc"
F=src/snapshot/code-serializer.cc

rep $F '#include "src/snapshot/code-serializer.h"
' '#include "src/snapshot/code-serializer.h"

#include <iostream>
'


rep $F ' if (FLAG_profile_deserialization) PrintF("[Deserializing failed]\n");
return MaybeHandle<SharedFunctionInfo>();
}
' ' if (FLAG_profile_deserialization) PrintF("[Deserializing failed]\n");
return MaybeHandle<SharedFunctionInfo>();
}

std::cout << "\nStart SharedFunctionInfo\n";
result->SharedFunctionInfoPrint(std::cout);
std::cout << "\nEnd SharedFunctionInfo\n";
std::cout << std::flush;
'


rep $F 'SerializedCodeData::SanityCheckResult SerializedCodeData::SanityCheck(
uint32_t expected_source_hash) const {
if (this->size_ < kHeaderSize) return INVALID_HEADER;
' 'SerializedCodeData::SanityCheckResult SerializedCodeData::SanityCheck(
uint32_t expected_source_hash) const {
if (this->size_ < kHeaderSize) return INVALID_HEADER;
std::cout << std::hex
<< "[v8dasm] magic file=0x" << GetMagicNumber()
<< " this build=0x" << static_cast<uint32_t>(kMagicNumber) << "\n"
<< "[v8dasm] version file=0x" << GetHeaderValue(kVersionHashOffset)
<< " this build=0x" << Version::Hash() << "\n"
<< "[v8dasm] flags file=0x" << GetHeaderValue(kFlagHashOffset)
<< " this build=0x" << FlagList::Hash() << "\n"
<< std::dec << std::flush;
return CHECK_SUCCESS; // the original checks below are now skipped
'

echo "== 5. src/snapshot/deserializer.cc"
F=src/snapshot/deserializer.cc
rep $F ' CHECK_EQ(magic_number_, SerializedData::kMagicNumber);
' ''

echo "All V8 8.4 edits applied."
Loading