Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
rycbar77 committed Jan 2, 2024
1 parent 72aeba0 commit d66716a
Show file tree
Hide file tree
Showing 2 changed files with 229 additions and 0 deletions.
142 changes: 142 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,144 @@
# V8-Bytecode-Disassemble
Disassemble V8 Ignition bytecode.

Test on linux.
## 0.Credit
Slightly modified from [v8dasm](https://github.com/noelex/v8dasm).

## 1.Modify V8 Source Code
In `code-serializer.cc`, insert the following lines after the serialization is completed (after maybe_result is successfully converted to result) in function `CodeSerializer::Deserialize`:

```c++
result->GetBytecodeArray(isolate).Disassemble(std::cout);
std::cout << std::flush;
```
Modify function `SharedFunctionInfo::SharedFunctionInfoPrint` in `objects-printer.cc`:
```diff
diff --git a/src/diagnostics/objects-printer.cc b/src/diagnostics/objects-printer.cc
index 2ec89d58962..7665668d8ae 100644
--- a/src/diagnostics/objects-printer.cc
+++ b/src/diagnostics/objects-printer.cc
@@ -1652,6 +1652,14 @@ void SharedFunctionInfo::SharedFunctionInfoPrint(std::ostream& os) {
os << "<none>";
}
os << "\n";
+
+ os << "\n; --- start SharedFunctionInfoDisassembly\n";
+ Isolate* isolate = GetIsolate();
+ if (this->HasBytecodeArray()) {
+ this->GetBytecodeArray(isolate).Disassemble(os);
+ os << std::flush;
+ }
+ os << "; --- end SharedFunctionInfoDisassembly\n";
}
```

Modify function HeapObject::HeapObjectShortPrint in objects.cc.

```diff
diff --git a/src/objects/objects.cc b/src/objects/objects.cc
index 4616ef7ab74..9b1e67a2f4a 100644
--- a/src/objects/objects.cc
+++ b/src/objects/objects.cc
@@ -1860,6 +1860,7 @@ void HeapObject::HeapObjectShortPrint(std::ostream& os) {
os << accumulator.ToCString().get();
return;
}
+ int len;
switch (map(cage_base).instance_type()) {
case MAP_TYPE: {
os << "<Map";
@@ -1941,11 +1942,27 @@ void HeapObject::HeapObjectShortPrint(std::ostream& os) {
<< "]>";
break;
case FIXED_ARRAY_TYPE:
- os << "<FixedArray[" << FixedArray::cast(*this).length() << "]>";
+ len = FixedArray::cast(*this).length();
+ os << "<FixedArray[" << len << "]>";
+
+ if (len) {
+ os << "\n; #region FixedArray\n";
+ FixedArray::cast(*this).FixedArrayPrint(os);
+ os << "; #endregion";
+ }
+
break;
case OBJECT_BOILERPLATE_DESCRIPTION_TYPE:
- os << "<ObjectBoilerplateDescription[" << FixedArray::cast(*this).length()
- << "]>";
+ len = FixedArray::cast(*this).length();
+ os << "<ObjectBoilerplateDescription[" << len << "]>";
+
+ if (len) {
+ os << "\n; #region ObjectBoilerplateDescription\n";
+ ObjectBoilerplateDescription::cast(*this)
+ .ObjectBoilerplateDescriptionPrint(os);
+ os << "; #endregion";
+ }
+
break;
case FIXED_DOUBLE_ARRAY_TYPE:
```

## Configure and Build V8
Make sure to check if the bytecode you have works with `Pointer Compression` or not.

For example, it will cause different length-of-steps when executing `CopySlots` fuction.

```c++
void CopySlots(Address* dest, int number_of_slots) {
base::AtomicWord* start = reinterpret_cast<base::AtomicWord*>(dest);
base::AtomicWord* end = start + number_of_slots;
for (base::AtomicWord* p = start; p < end;
++p, position_ += sizeof(base::AtomicWord)) {
base::AtomicWord val;
memcpy(&val, data_ + position_, sizeof(base::AtomicWord));
base::Relaxed_Store(p, val);
}
}

#ifdef V8_COMPRESS_POINTERS
void CopySlots(Tagged_t* dest, int number_of_slots) {
AtomicTagged_t* start = reinterpret_cast<AtomicTagged_t*>(dest);
AtomicTagged_t* end = start + number_of_slots;
for (AtomicTagged_t* p = start; p < end;
++p, position_ += sizeof(AtomicTagged_t)) {
AtomicTagged_t val;
memcpy(&val, data_ + position_, sizeof(AtomicTagged_t));
base::Relaxed_Store(p, val);
}
}
#endif
```
Configure with the following arguments if `Pointer Compression` is disabled.
```
is_debug = false
target_cpu = "x64"
v8_enable_backtrace = true
v8_enable_slow_dchecks = true
v8_optimized_debug = false
is_component_build = false
v8_static_library = true
v8_enable_disassembler = true
v8_enable_object_print = true
use_custom_libcxx = false
use_custom_libcxx_for_host = false
v8_use_external_startup_data = false
enable_iterator_debugging = false
use_goma=false
goma_dir="None"
v8_enable_pointer_compression = false
```
## Custom Code Cache loader
Write a program to call `ScriptCompiler::CompileUnboundScript` to load code cache from file. `v8dasm.cpp` is a sample program for linux.
Build
```bash
clang++ v8dasm.cpp -std=c++17 -I../../include -Lobj -lv8_libbase -lv8_libplatform -lv8_base_without_compiler -lwee8 -o v8dasm
```
87 changes: 87 additions & 0 deletions v8dasm.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#include <libplatform/libplatform.h>
#include <v8.h>

#include <string>

using namespace v8;

static Isolate* isolate = nullptr;

static v8::ScriptCompiler::CachedData* compileCode(const char* data) {
auto str = String::NewFromUtf8(isolate, data).ToLocalChecked();
auto script =
Script::Compile(isolate->GetCurrentContext(), str).ToLocalChecked();
auto unboundScript = script->GetUnboundScript();

return ScriptCompiler::CreateCodeCache(unboundScript);
}

static void fixBytecode(uint8_t* bytecodeBuffer, const char* code) {
auto dummyBytecode = compileCode(code);
// Copy version hash, source hash and flag hash from dummy bytecode to source
// bytecode. Offsets of these value may differ in different version of V8.
// Refer V8 src/snapshot/code-serializer.h for details.
for (int i = 4; i < 16; i++) {
bytecodeBuffer[i] = dummyBytecode->data[i];
}
delete dummyBytecode;
}

static void runBytecode(uint8_t* bytecodeBuffer, int len) {
// Compile some dummy code to get version hash, source hash and flag hash.
const char* code = "console.log('hello');";
fixBytecode(bytecodeBuffer, code);

// Load code into code cache.
auto cached_data = new ScriptCompiler::CachedData(bytecodeBuffer, len);

// Create dummy source.
ScriptOrigin origin(isolate, String::NewFromUtf8Literal(isolate, "code.jsc"));
ScriptCompiler::Source source(
String::NewFromUtf8(isolate, code).ToLocalChecked(), origin, cached_data);

// Compile code from code cache to print disassembly.
MaybeLocal<UnboundScript> v8_script = ScriptCompiler::CompileUnboundScript(
isolate, &source, ScriptCompiler::kConsumeCodeCache);
}

static void readAllBytes(const std::string& file, std::vector<char>& buffer) {
std::ifstream infile(file, std::ifstream::binary);

infile.seekg(0, infile.end);
size_t length = infile.tellg();
infile.seekg(0, infile.beg);

if (length > 0) {
buffer.resize(length);
infile.read(&buffer[0], length);
}
}

int main(int argc, char* argv[]) {
// Set flags here, flags that affects code generation and seririalzation
// should be same as the target program. You can add other flags freely
// because flag hash will be overrided in fixBytecode().
v8::V8::SetFlagsFromString("--no-lazy --no-flush-bytecode --log-all");

v8::V8::InitializeICUDefaultLocation(argv[0]);
v8::V8::InitializeExternalStartupData(argv[0]);
auto plat = v8::platform::NewDefaultPlatform();
v8::V8::InitializePlatform(plat.get());
v8::V8::Initialize();

Isolate::CreateParams p = {};
p.array_buffer_allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator();

isolate = Isolate::New(p);
{
v8::Isolate::Scope isolate_scope(isolate);
v8::HandleScope scope(isolate);
auto ctx = v8::Context::New(isolate);
Context::Scope context_scope(ctx);

std::vector<char> data;
readAllBytes(argv[1], data);
runBytecode((uint8_t*)data.data(), data.size());
}
}

0 comments on commit d66716a

Please sign in to comment.