From d6a1d5760c58945ef7230aa7dc31f91ce97fc367 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Sun, 18 Mar 2018 21:27:55 +0800 Subject: [PATCH 1/3] configure: skip linking tools/gyp if it exists Use the existing tools/gyp if it exists. It could be checked out from source instead of being linked to the node-gyp installation. Also corrects the names in the gyp linking routines. Also tries to find the built library in out/Release/obj.target/ if it's not in out/Release/ --- scripts/cleanup.js | 19 ++++++++++++++++--- scripts/configure.js | 31 ++++++++++++++++++++----------- 2 files changed, 36 insertions(+), 14 deletions(-) diff --git a/scripts/cleanup.js b/scripts/cleanup.js index 6614c8d9..40be657e 100644 --- a/scripts/cleanup.js +++ b/scripts/cleanup.js @@ -2,6 +2,7 @@ const os = require('os'); const child_process = require('child_process'); +const fs = require('fs'); const cwd = process.cwd(); const osName = os.type(); @@ -12,11 +13,23 @@ if (osName === 'Darwin') { } const llnodeLib = `llnode.${libExt}`; +const buildType = 'Release'; // Move the library somewhere easy to remember. -console.log(`Copying ${cwd}/out/Release/${llnodeLib} to ${cwd}/${llnodeLib}`); -child_process.execSync(`mv ${cwd}/out/Release/${llnodeLib} ${cwd}/${llnodeLib}`); +// TODO: get build type from somewhere else? + +const outputDir = `${cwd}/out/${buildType}` +let buildPath = `${outputDir}/${llnodeLib}`; +const finalPath = `${cwd}/${llnodeLib}`; + +if (!fs.existsSync(buildPath)) { + // Original gyp does not move the result + buildPath = `${outputDir}/obj.target/${llnodeLib}`; +} + +console.log(`Copying ${buildPath} to ${finalPath}`); +child_process.execSync(`mv ${buildPath} ${finalPath}`); console.log(`${os.EOL}llnode plugin installed, load in lldb with:`); -console.log(`(lldb) plugin load ${cwd}/${llnodeLib}`); +console.log(`(lldb) plugin load ${finalPath}`); console.log(`or copy plugin to lldb system plugin directory, see www.npmjs.org/llnode${os.EOL}`); diff --git a/scripts/configure.js b/scripts/configure.js index c9c5b582..19b31b14 100644 --- a/scripts/configure.js +++ b/scripts/configure.js @@ -13,8 +13,10 @@ function main() { const osName = os.type(); const installation = configureInstallation(osName, buildDir); linkHeadersDir(installation.prefix); - const gypDir = getGypDir(buildDir); - linkGyp(gypDir); + const nodeGypDir = getNodeGyp(buildDir); + if (nodeGypDir !== undefined) { // otherwise use tools/gyp + linkNodeGyp(nodeGypDir); + } writeLlnodeScript(buildDir, installation.executable, osName); // Exit with success. process.exit(0); @@ -94,10 +96,15 @@ function linkHeadersDir(lldbInstallDir) { } /** - * Get the path to the GYP installation - * @param {string} buildDir Path of the project directory + * Get the path to node-gyp installation. Return undefined if tools/gyp + * exists (possibly already checked out from the gyp source). + * @param {string|undefined} buildDir Path of the project directory */ -function getGypDir(buildDir) { +function getNodeGyp(buildDir) { + if (fs.existsSync(path.join(buildDir, 'tools', 'gyp'))) { + console.log('Found tools/gyp, skip creating the symlink.') + return undefined; + } // npm explore has a different root folder when using -g // So we are tacking on the extra the additional subfolders let gypSubDir = 'node-gyp'; @@ -125,13 +132,15 @@ function getGypDir(buildDir) { /** * Link tools/gyp to the GYP installation - * @param {string} gypDir path to the GYP installation + * @param {string} nodeGypDir path to node-gyp */ -function linkGyp(gypDir) { - child_process.execSync('rm -rf tools'); - fs.mkdirSync('tools'); - console.log(`Linking tools/gyp to ${gypDir}/gyp`); - fs.symlinkSync(`${gypDir}/gyp`, 'tools/gyp'); +function linkNodeGyp(nodeGypDir) { + if (nodeGypDir !== undefined) { + child_process.execSync('rm -rf tools'); + fs.mkdirSync('tools'); + console.log(`Linking tools/gyp to ${nodeGypDir}/gyp`); + fs.symlinkSync(`${nodeGypDir}/gyp`, 'tools/gyp'); + } } /** From a81f1815578b2252a48cfb8532a328339eadb090 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Sun, 18 Mar 2018 23:28:41 +0800 Subject: [PATCH 2/3] src: format the src using clang-format 5.0.1 --- src/llscan.cc | 6 ++---- src/llscan.h | 4 ++-- src/llv8-constants.cc | 4 ++-- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/llscan.cc b/src/llscan.cc index dd2a6a7d..c91af2bb 100644 --- a/src/llscan.cc +++ b/src/llscan.cc @@ -1280,8 +1280,7 @@ bool LLScan::ScanHeapForObjects(lldb::SBTarget target, return true; } -std::string -FindJSObjectsVisitor::MapCacheEntry::GetTypeNameWithProperties( +std::string FindJSObjectsVisitor::MapCacheEntry::GetTypeNameWithProperties( ShowArrayLength show_array_length, size_t max_properties) { std::string type_name_with_properties(type_name); @@ -1306,8 +1305,7 @@ FindJSObjectsVisitor::MapCacheEntry::GetTypeNameWithProperties( bool FindJSObjectsVisitor::MapCacheEntry::Load(v8::Map map, v8::HeapObject heap_object, - v8::LLV8* llv8, - v8::Error& err) { + v8::LLV8* llv8, v8::Error& err) { // Check type first is_histogram = FindJSObjectsVisitor::IsAHistogramType(map, err); diff --git a/src/llscan.h b/src/llscan.h index b1cf1abb..df1aaf5d 100644 --- a/src/llscan.h +++ b/src/llscan.h @@ -257,8 +257,8 @@ class FindJSObjectsVisitor : MemoryVisitor { ShowArrayLength show_array_length = kShowArrayLength, size_t max_properties = 0); - bool Load(v8::Map map, v8::HeapObject heap_object, - v8::LLV8* llv8, v8::Error& err); + bool Load(v8::Map map, v8::HeapObject heap_object, v8::LLV8* llv8, + v8::Error& err); }; static bool IsAHistogramType(v8::Map& map, v8::Error& err); diff --git a/src/llv8-constants.cc b/src/llv8-constants.cc index 4dc1a6e4..f805de24 100644 --- a/src/llv8-constants.cc +++ b/src/llv8-constants.cc @@ -32,8 +32,8 @@ void Module::Assign(SBTarget target, Common* common) { template -T ReadSymbolFromTarget(SBTarget& target, SBAddress& start, - const char* name, Error& err) { +T ReadSymbolFromTarget(SBTarget& target, SBAddress& start, const char* name, + Error& err) { SBError sberr; T res = 0; target.ReadMemory(start, &res, sizeof(T), sberr); From 0943fdc1581ffad01cd8eb7f4e7deb5c0561370f Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Sun, 18 Mar 2018 23:30:30 +0800 Subject: [PATCH 3/3] docs: split the README and update CONTRIBUTING.md - Split the README into install.md, usage.md and develop.md under docs/. - Added OS-specific instructions on how to set up the prerequisites - Update the Contributing guide so it applies to llnode instead of node core. - Added instruction on how to install and run clang-format. Prefer the one available in the LLVM website. --- CONTRIBUTING.md | 43 +++---- README.md | 293 +++---------------------------------------- docs/develop.md | 98 +++++++++++++++ docs/installation.md | 151 ++++++++++++++++++++++ docs/usage.md | 151 ++++++++++++++++++++++ 5 files changed, 437 insertions(+), 299 deletions(-) create mode 100644 docs/develop.md create mode 100644 docs/installation.md create mode 100644 docs/usage.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index be52c859..7c43b390 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,7 +2,7 @@ This document will guide you through the contribution process. -### Step 1: Fork +## Step 1: Fork Fork the project [on GitHub](https://github.com/indutny/llnode) and check out your copy locally. @@ -13,12 +13,12 @@ $ cd llnode $ git remote add upstream git://github.com/indutny/llnode.git ``` -#### Which branch? +### Which branch? For developing new features and bug fixes, the `master` branch should be pulled and built upon. -### Step 2: Branch +## Step 2: Branch Create a feature branch and start hacking: @@ -26,7 +26,19 @@ Create a feature branch and start hacking: $ git checkout -b my-feature-branch -t origin/master ``` -### Step 3: Commit +### Step 3: Develop and Test + +For guidance on how to run the tests for the llnode project, see this +[guide](./docs/develop.md). + +Bug fixes and features **should come with tests**. Add your tests in the +`test/` directory. Looking at other tests to see how they should be +structured can also help. + +Make sure to install clang-format and run `make format` in the project +directory before committing the patch. + +## Step 4: Commit Make sure git knows your name and email address: @@ -69,10 +81,10 @@ If your patch fixes an open issue, you can add a reference to it at the end of the log. Use the `Fixes:` prefix and the full issue URL. For example: ``` -Fixes: https://github.com/indutny/llnode/issues/1337 +Fixes: https://github.com/nodejs/llnode/issues/1337 ``` -### Step 4: Rebase +## Step 5: Rebase Use `git rebase` (not `git merge`) to sync your work from time to time. @@ -81,22 +93,7 @@ $ git fetch upstream $ git rebase upstream/master ``` - -### Step 5: Test - -Bug fixes and features **should come with tests**. Add your tests in the -`test/parallel/` directory. For guidance on how to write a test for the llnode -project, see this [guide](./doc/guides/writing_tests.md). Looking at other tests -to see how they should be structured can also help. - -```text -$ npm install && npm test -``` - -Make sure the linter is happy and that all tests pass. Please, do not submit -patches that fail either check. - -### Step 6: Push +## Step 6: Push ```text $ git push origin my-feature-branch @@ -114,7 +111,7 @@ not send out notifications when you add commits. The [Node.js Code of Conduct][] applies to this repo. -[Node.js Code of Conduct]: https://github.com/nodejs/node/blob/master/CODE_OF_CONDUCT.md +[Node.js Code of Conduct]: https://github.com/nodejs/admin/blob/master/CODE_OF_CONDUCT.md ## Code Contributions diff --git a/README.md b/README.md index a64ea7fd..986d7148 100644 --- a/README.md +++ b/README.md @@ -17,294 +17,35 @@ The llnode plugin adds the ability to inspect JavaScript stack frames, objects, source code and more to the standard C/C++ debugging facilities when working with Node.js processes or core dumps in LLDB. -## Demo +## Quick start -https://asciinema.org/a/29589 +Demo: https://asciinema.org/a/29589 -### Quick start - -Start an LLDB session with the llnode plugin automatically loaded: - -```bash -npm install -g llnode -llnode `which node` -c /path/to/core/dump -``` - -- For more details on starting llnode see the [Usage](#usage) section. -- To get started with the llnode commands see the [Commands](#commands) section. - -## Install Instructions - -### Prerequisites: Install LLDB and its Library - -To use llnode you need to have the LLDB debugger installed. The recommended -version is LLDB 3.9 and above. - -- OS X/macOS - - You can install [Xcode](https://developer.apple.com/xcode/) and use the - LLDB that comes with it. - - Optionally, you can install newer versions of lldb using Homebrew with - - ```bash - brew update && brew install --with-lldb --with-toolchain llvm - ``` - - and make sure `/usr/local/opt/llvm/bin` gets searched before `/usr/bin/` - on your `PATH`. llnode will link to the LLDB installation returned by - `llvm-config` if available. -- Linux - - You can install the lldb package using the package manager of your - distribution. You may need to install additional packages for `liblldb` - as well. - - For example, on Ubuntu 16.04 you can install the prerequisites with - - ```bash - apt-get install lldb-4.0 liblldb-4.0-dev - ``` -- FreeBSD - - ```bash - # Install llvm with lldb and headers - pkg install llvm39 - rm -f /usr/bin/lldb - ln -s /usr/local/bin/lldb39 /usr/bin/lldb - ``` - -### Install the Plugin - -#### Install llnode globally via npm - -If you have `lldb` available on your `PATH`, simply run: - -```bash -npm install -g llnode -``` - -To use a particular build of lldb, use the `--lldb_exe` option. For example, -on Linux the executable on the `PATH` might be `lldb-3.9`: - -```bash -npm install --lldb_exe=`which lldb-3.9` -g llnode -``` - -After installing with npm, `llnode` should be available on your `PATH` as a -shortcut for running LLDB with the llnode plugin. - -#### Optional: Install with Homebrew (OS X/macOS) +With the [prerequisites](docs/installation.md#prerequisites) installed, +start an lldb session with the llnode plugin automatically loaded: ```bash -brew install llnode -``` - -## Loading the llnode Plugin - -There are several ways to load the llnode plugin: - -### 1. Using the llnode shortcut - -If you install llnode globally via npm (`npm install -g llnode`), you can use -the `llnode` shortcut script. This starts `lldb` and automatically issues -the `plugin load` command. All parameters to the llnode script are passed -directly to lldb. If you it's not a local installation, the shortcut will be in -`node_modules/.bin/llnode`. - -### 2. Using `~/.lldbinit` to load the Plugin Automatically - -To tell LLDB to load llnode automatically regardless of the -version of lldb that you are running, add this line to `~/.lldbinit`: - -``` -plugin load /path/to/the/llnode/plugin -``` - -The path to the llnode plugin should be printed when the installation -is finished. On OS X/macOS the plugin is typically -`node_modules/llnode/llnode.dylib`, on Linux it's -`node_modules/llnode/llnode.so`. - -### 3. Loading the Plugin Manually - -The llnode plugin can also be manually loaded into LLDB using the -`plugin load` command within lldb. - -It does not matter whether the `plugin load` command is issued before or after -loading a core dump or attaching to a process. - -### 4. Install the Plugin to the LLDB System Plugin Directory - -Similar to the `~/.lldbinit` approach, this way LLDB will also load the plugin -automatically on start-up. Doing this may require additional permissions -to be able to copy the plugin libary to the system plugin directory. - -On Linux, run `make install-linux` in the project directory, or if -installing with npm, copy `node_modules/llnode/llnode.so` -to `/usr/lib/lldb/plugins` or create a link there. - -On OS X/macOS, run `make install-osx` in the project directory, or if -installing with npm, copy `node_modules/llnode/llnode.dylib` -to `~/Library/Application\ Support/LLDB/PlugIns/` or create a link there. - -# Usage - -To use llnode with a core dump the core dump needs to be loaded into lldb -along with the exact executable that created the core dump. The executable -contains information that lldb and the llnode plugin need to make sense of -the data in the core dump. - -To load a core dump when starting llnode use: -``` -llnode /path/to/bin/node -c /path/to/core -``` -or to load the core dump after starting lldb: +npm install -g llnode # installs llnode +# Load a core dump +llnode /path/to/node -c /path/to/core/dump +# Or, run a Node.js script with --abort_on_uncaught_exceptions +llnode -- /path/to/node --abort_on_uncaught_exceptions /path/to/node/script ``` -(llnode) target create /path/to/bin/node -c /path/to/core -``` - -To use llnode against a live process: -``` -llnode -- /path/to/bin/node script.js -(llnode) run -``` -This is ideal for debugging an npm package with native code. -To debug a Node.js crash on uncaught exception: -``` -llnode -- /path/to/bin/node --abort_on_uncaught_exception script.js -(llnode) run -``` -lldb will stop your process when it crashes. To see where it stopped use the -v8 bt command. See the [Commands](#commands) section below for more commands. - -### Commands - -``` -(llnode) v8 help - Node.js helpers - -Syntax: v8 - -The following subcommands are supported: - - bt -- Show a backtrace with node.js JavaScript functions and their args. An optional argument is accepted; if - that argument is a number, it specifies the number of frames to display. Otherwise all frames will be - dumped. - Syntax: v8 bt [number] - findjsinstances -- List every object with the specified type name. - Use -v or --verbose to display detailed `v8 inspect` output for each object. - Accepts the same options as `v8 inspect` - findjsobjects -- List all object types and instance counts grouped by typename and sorted by instance count. Use - -d or --detailed to get an output grouped by type name, properties, and array length, as well as - more information regarding each type. - With lldb < 3.9, requires the `LLNODE_RANGESFILE` environment variable to be set to a file - containing memory ranges for the core file being debugged. - There are scripts for generating this file on Linux and Mac in the scripts directory of the llnode - repository. - findrefs -- Finds all the object properties which meet the search criteria. - The default is to list all the object properties that reference the specified value. - Flags: +## Install llnode - * -v, --value expr - all properties that refer to the specified JavaScript object (default) - * -n, --name name - all properties with the specified name - * -s, --string string - all properties that refer to the specified JavaScript string value +See [Installing llnode](docs/installation.md). - inspect -- Print detailed description and contents of the JavaScript value. +## Using the llnode plugin - Possible flags (all optional): - - * -F, --full-string - print whole string without adding ellipsis - * -m, --print-map - print object's map address - * -s, --print-source - print source code for function objects - * -l num, --length num - print maximum of `num` elements from string/array - - Syntax: v8 inspect [flags] expr - nodeinfo -- Print information about Node.js - print -- Print short description of the JavaScript value. - - Syntax: v8 print expr - source -- Source code information - -For more help on any particular subcommand, type 'help '. -``` +- For more details on starting llnode see + [Loading the llnode Plugin](docs/usage.md#loading-the-llnode-plugin). +- To get started with the llnode commands see + [Commands](docs/usage.md#commands). ## Develop and Test -### Configure and Build - -The easiest way to build the plugin: - -```bash -# Clone this repo -git clone https://github.com/nodejs/llnode.git && cd llnode - -# Configure and build the plugin -npm install -# Or run -make plugin -``` - -To configure the build yourself: - -```bash -# Detect available LLDB installation and download headers if necessary -node scripts/configure.js - -# To configure with the detected LLDB installation -./gyp_llnode -# To configure with a specified LLDB installation on OS X/macOS -./gyp_llnode -Dlldb_build_dir=/usr/local/Cellar/llvm/5.0.0 -# To configure with a specified LLDB installation on Linux -./gyp_llnode -Dlldb_dir=/usr/lib/llvm-3.9/ -# To configure with a specified LLDB installation on FreeBSD -./gyp_llnode -Dlldb_dir=/usr/local/llvm39/ - -# Build -make -C out/ -j9 - -# Move the built plugin to the project directory -node scripts/cleanup.js -``` - -### Test - -To run the tests, if `lldb` is an executable on the `PATH`: - -```bash -npm run test -``` - -If the LLDB executable is named differently, point `TEST_LLDB_BINARY` -to it: - -```bash -TEST_LLDB_BINARY=`which lldb-4.0` npm run test -``` - -### Useful Environment Variables - -* `LLNODE_DEBUG=true` to see additional debug info from llnode -* `TEST_LLNODE_DEBUG=true` to see additional debug info coming from the tests -* `LLNODE_CORE=/path/to/core/dump LLNODE_NODE_EXE=/path/to/node LLNODE_NO_RANGES=true` - to use a prepared core dump instead of generating one on-the-fly when running - the tests. - -For example, to inspect the process of `inspect-scenario.js`, run: - -```bash -LLNODE_DEBUG=true lldb -- \ - node --abort_on_uncaught_exception --expose_externalize_string \ - test/fixtures/inspect-scenario.js -(lldb) run -``` - -To debug `test/scan-test.js` with a prepared core dump: - -``` -LLNODE_DEBUG=true TEST_LLNODE_DEBUG=true \ - LLNODE_CORE=/path/to/core/dump/of/inspect/scenario.js \ - LLNODE_NODE_EXE=/path/to/node \ - LLNODE_NO_RANGES=true \ - node test/scan-test.js -``` +See [Develop the llnode plugin](docs/develop.md). ## LICENSE diff --git a/docs/develop.md b/docs/develop.md new file mode 100644 index 00000000..4f70d708 --- /dev/null +++ b/docs/develop.md @@ -0,0 +1,98 @@ + +# Develop the llnode plugin + + + +- [Configure and Build](#configure-and-build) +- [Run the tests](#run-the-tests) +- [Useful Environment Variables](#useful-environment-variables) +- [Running clang-format](#running-clang-format) + + + +## Configure and Build + +The easiest way to build the plugin: + +```bash +# Clone this repo +git clone https://github.com/nodejs/llnode.git && cd llnode + +# Configure and build the plugin +npm install +# Or run +make plugin +``` + +To configure the build yourself: + +```bash +# Detect available LLDB installation and download headers if necessary +node scripts/configure.js + +# To configure with the detected LLDB installation +./gyp_llnode +# To configure with a specified LLDB installation on OS X/macOS +./gyp_llnode -Dlldb_build_dir=/usr/local/Cellar/llvm/5.0.0 +# To configure with a specified LLDB installation on Linux +./gyp_llnode -Dlldb_dir=/usr/lib/llvm-3.9/ +# To configure with a specified LLDB installation on FreeBSD +./gyp_llnode -Dlldb_dir=/usr/local/llvm39/ + +# Build +make -C out/ -j9 + +# Move the built plugin to the project directory +node scripts/cleanup.js +``` + +## Run the tests + +To run the tests, if `lldb` is an executable on the `PATH`: + +```bash +npm run test +``` + +If the LLDB executable is named differently, point `TEST_LLDB_BINARY` +to it: + +```bash +TEST_LLDB_BINARY=`which lldb-4.0` npm run test +``` + +## Useful Environment Variables + +* `LLNODE_DEBUG=true` to see additional debug info from llnode +* `TEST_LLNODE_DEBUG=true` to see additional debug info coming from the tests +* `LLNODE_CORE=/path/to/core/dump LLNODE_NODE_EXE=/path/to/node LLNODE_NO_RANGES=true` + to use a prepared core dump instead of generating one on-the-fly when running + the tests. + +For example, to inspect the process of `inspect-scenario.js`, run: + +```bash +LLNODE_DEBUG=true lldb -- \ + node --abort_on_uncaught_exception --expose_externalize_string \ + test/fixtures/inspect-scenario.js +(lldb) run +``` + +To debug `test/scan-test.js` with a prepared core dump: + +``` +LLNODE_DEBUG=true TEST_LLNODE_DEBUG=true \ + LLNODE_CORE=/path/to/core/dump/of/inspect/scenario.js \ + LLNODE_NODE_EXE=/path/to/node \ + LLNODE_NO_RANGES=true \ + node test/scan-test.js +``` + +## Running clang-format + +We use the clang-format tool to format our C++ code. Run `make format` to +format the code base before submitting changes. + +You can download clang-format from [LLVM's website](http://releases.llvm.org/download.html). +Extract the xz file and copy `bin/clang-format` to somewhere that can be searched in +your `$PATH` so that `clang-format` is available in the command line. diff --git a/docs/installation.md b/docs/installation.md new file mode 100644 index 00000000..cf191874 --- /dev/null +++ b/docs/installation.md @@ -0,0 +1,151 @@ +# Installing llnode + + + +- [Prerequisites](#prerequisites) + - [OS X/macOS](#os-xmacos) + - [Ubuntu/Debian](#ubuntudebian) + - [Fedora](#fedora) + - [CentOS / RHEL](#centos--rhel) + - [FreeBSD](#freebsd) +- [Install the Plugin](#install-the-plugin) + - [Install llnode globally via npm](#install-llnode-globally-via-npm) + - [Alternative: Install with Homebrew (OS X/macOS)](#alternative-install-with-homebrew-os-xmacos) + - [Alternative: build the plugin from source](#alternative-build-the-plugin-from-source) + + + +## Prerequisites + +To build llnode, you need: + +- Node.js v4.x or later (latest stable is preferred, the version of Node.js + that you use to build llnode is not relevant to the version of Node.js + that you need to debug your core dump or script with). +- gyp: if you are installing with npm, you can use node-gyp and install it with + `npm install -g node-gyp`. If you are from source, you can either use node-gyp + or in the llnode project directory, run + + ``` + git clone https://chromium.googlesource.com/external/gyp.git tools/gyp + ``` + +Other than Node.js and gyp, you also need: + +- The lldb debugger and its library, usually available in a + `lldb` or `llvm` package. The recommended version is lldb 3.9 and above. + The latest stable version is preferred. +- GNU Make +- Python (v2.7 recommended) +- Usable C and C++ compilers specified with `CC` and `CXX` environment variables + +### OS X/macOS + +If you have [Xcode](https://developer.apple.com/xcode/) and the command line +tools installed, you can use the lldb and make that come with it. + +Optionally, you can install newer versions of lldb and make using Homebrew with + +```bash +brew update && brew install make --with-lldb --with-toolchain llvm +``` + +and make sure `/usr/local/opt/llvm/bin` gets searched before `/usr/bin/` +in your `PATH`. llnode will link to the lldb installation returned by +`llvm-config` if available. + +### Ubuntu/Debian + +See [LLVM's website](http://apt.llvm.org/) on how to install lldb on +Debian-based distributions. + +For example, on Ubuntu 16.04 you can set up the environment with: + +```bash +apt-get update && apt-get install clang-4.0 lldb-4.0 liblldb-4.0-dev make +# Configure environment variables for compilers +export CC=clang-4.0 +export CXX=clang++-4.0 +``` + +### Fedora + +For example, on Fedora 27, you can set up the environment with: + +```bash +yum install llvm lldb python clang make +# Or, if you use dnf +dnf install llvm lldb python clang make +# Configure environment variables for compilers +export CC=clang +export CXX=clang++ +``` + +### CentOS / RHEL + +For example, on CentOS 7, if you use the Linux Software Collections, +you can set up the environment with: + +```bash +yum install centos-release-scl # This installs the SCL license +yum install llvm-toolset-7 +# Enters the bash with llvm-toolset-7 enabled to start installation +# before building llnode +scl enable llvm-toolset-7 bash +# Configure environment variables for compilers +export CC=clang +export CXX=clang++ +``` + +### FreeBSD + +For example, on FreeBSD 11, you can set up the environment with: + +```bash +# Install llvm with lldb and headers +pkg install llvm50 gmake python +# Remove the link to the default installation which is 4.0 for FreeBSD 11 +rm -f /usr/bin/lldb +# Relink to lldb 5.0 +ln -s /usr/local/bin/lldb50 /usr/bin/lldb +# Configure environment variables for compilers +export CC=clang +export CXX=clang++ +``` + +## Install the Plugin + +### Install llnode globally via npm + +If you have `lldb` available on your `PATH`, simply run: + +```bash +npm install -g llnode +``` + +To use a particular build of lldb, use the `--lldb_exe` option. For example, +on Linux the executable on the `PATH` might be `lldb-3.9`: + +```bash +npm install --lldb_exe=`which lldb-3.9` -g llnode +``` + +After installing with npm, `llnode` should be available on your `PATH` as a +shortcut for running lldb with the llnode plugin. + +### Alternative: Install with Homebrew (OS X/macOS) + +```bash +brew install llnode +``` + +### Alternative: build the plugin from source + +```bash +git clone https://github.com/nodejs/llnode.git +cd llnode && make plugin + +# Or, if you are on a BSD, use GNU make instead of the BSD make +# You might need to pkg install gmake if it's not installed +cd llnode && gmake plugin +``` diff --git a/docs/usage.md b/docs/usage.md new file mode 100644 index 00000000..474b0bc9 --- /dev/null +++ b/docs/usage.md @@ -0,0 +1,151 @@ + +# Usage + + + +- [Loading the llnode Plugin](#loading-the-llnode-plugin) + - [1. Using the llnode shortcut](#1-using-the-llnode-shortcut) + - [2. Using `~/.lldbinit` to load the Plugin Automatically](#2-using-lldbinit-to-load-the-plugin-automatically) + - [3. Loading the Plugin Manually](#3-loading-the-plugin-manually) + - [4. Install the Plugin to the LLDB System Plugin Directory](#4-install-the-plugin-to-the-lldb-system-plugin-directory) +- [Starting the command line](#starting-the-command-line) +- [Commands](#commands) + + + +## Loading the llnode Plugin + +There are several ways to load the llnode plugin: + +### 1. Using the llnode shortcut + +If you install llnode globally via npm (`npm install -g llnode`), you can use +the `llnode` shortcut script. This starts `lldb` and automatically issues +the `plugin load` command. All parameters to the llnode script are passed +directly to lldb. If you it's not a local installation, the shortcut will be in +`node_modules/.bin/llnode`. + +### 2. Using `~/.lldbinit` to load the Plugin Automatically + +To tell LLDB to load llnode automatically regardless of the +version of lldb that you are running, add this line to `~/.lldbinit`: + +``` +plugin load /path/to/the/llnode/plugin +``` + +The path to the llnode plugin should be printed when the installation +is finished. On OS X/macOS the plugin is typically +`node_modules/llnode/llnode.dylib`, on Linux it's +`node_modules/llnode/llnode.so`. + +### 3. Loading the Plugin Manually + +The llnode plugin can also be manually loaded into LLDB using the +`plugin load` command within lldb. + +It does not matter whether the `plugin load` command is issued before or after +loading a core dump or attaching to a process. + +### 4. Install the Plugin to the LLDB System Plugin Directory + +Similar to the `~/.lldbinit` approach, this way LLDB will also load the plugin +automatically on start-up. Doing this may require additional permissions +to be able to copy the plugin libary to the system plugin directory. + +On Linux, run `make install-linux` in the project directory, or if +installing with npm, copy `node_modules/llnode/llnode.so` +to `/usr/lib/lldb/plugins` or create a link there. + +On OS X/macOS, run `make install-osx` in the project directory, or if +installing with npm, copy `node_modules/llnode/llnode.dylib` +to `~/Library/Application\ Support/LLDB/PlugIns/` or create a link there. + +## Starting the command line + +To use llnode with a core dump the core dump needs to be loaded into lldb +along with the exact executable that created the core dump. The executable +contains information that lldb and the llnode plugin need to make sense of +the data in the core dump. + +To load a core dump when starting llnode use: + +``` +llnode /path/to/bin/node -c /path/to/core +``` + +or to load the core dump after starting lldb: + +``` +(llnode) target create /path/to/bin/node -c /path/to/core +``` + +To use llnode against a live process: + +``` +llnode -- /path/to/bin/node script.js +(llnode) run +``` + +This is ideal for debugging an npm package with native code. +To debug a Node.js crash on uncaught exception: + +``` +llnode -- /path/to/bin/node --abort_on_uncaught_exception script.js +(llnode) run +``` + +lldb will stop your process when it crashes. To see where it stopped use the +v8 bt command. See the [Commands](#commands) section below for more commands. + +## Commands + +``` +(llnode) v8 help + Node.js helpers + +Syntax: v8 + +The following subcommands are supported: + + bt -- Show a backtrace with node.js JavaScript functions and their args. An optional argument is accepted; if + that argument is a number, it specifies the number of frames to display. Otherwise all frames will be + dumped. + + Syntax: v8 bt [number] + findjsinstances -- List every object with the specified type name. + Use -v or --verbose to display detailed `v8 inspect` output for each object. + Accepts the same options as `v8 inspect` + findjsobjects -- List all object types and instance counts grouped by typename and sorted by instance count. Use + -d or --detailed to get an output grouped by type name, properties, and array length, as well as + more information regarding each type. + With lldb < 3.9, requires the `LLNODE_RANGESFILE` environment variable to be set to a file + containing memory ranges for the core file being debugged. + There are scripts for generating this file on Linux and Mac in the scripts directory of the llnode + repository. + findrefs -- Finds all the object properties which meet the search criteria. + The default is to list all the object properties that reference the specified value. + Flags: + + * -v, --value expr - all properties that refer to the specified JavaScript object (default) + * -n, --name name - all properties with the specified name + * -s, --string string - all properties that refer to the specified JavaScript string value + + inspect -- Print detailed description and contents of the JavaScript value. + + Possible flags (all optional): + + * -F, --full-string - print whole string without adding ellipsis + * -m, --print-map - print object's map address + * -s, --print-source - print source code for function objects + * -l num, --length num - print maximum of `num` elements from string/array + + Syntax: v8 inspect [flags] expr + nodeinfo -- Print information about Node.js + print -- Print short description of the JavaScript value. + + Syntax: v8 print expr + source -- Source code information + +For more help on any particular subcommand, type 'help '. +```