# BST-TIMEOUT: 300 . "$BST_LIB" # Google Breakpad 2023.06.01 (meta-oe recipes-devtools/breakpad with this # layer's bbappend) on wasm32-hwjs -- the PROCESSOR half. Numbered with the # other binary-format readers on this image (pax-utils, libtar, protobuf, # flatbuffers). # # THE PASS CRITERION IS UPSTREAM'S OWN, WHICH IS RARE AND IS THE POINT OF THIS # SUITE. Breakpad ships minidump2.dmp -- a real x86 Windows crash dump taken in # 2007 -- together with the exact stdout its own processors must produce from it, # and drives them from check_SCRIPTS as # ` ... | tr -d '\015' | diff -u -`. Sections 3-5 below run # those three comparisons on the target, byte for byte, against the references # installed from ${S} by the same build that produced the binaries. So this suite # does not assert what we think correct output looks like; it asserts that this # wasm32 build is INDISTINGUISHABLE from upstream's on 706 lines of stream dump # and on four walked frames with symbol resolution and CFI. # # WHY THAT IS MEANINGFUL ON A TARGET THAT CANNOT PRODUCE A MINIDUMP. A minidump # is a fixed little-endian binary format; reading one is pointer arithmetic, # bounds checks and a postfix-expression evaluator over CFI records. Every one of # those is a place where a 32-bit wasm target with a different pointer width, a # different std::string and a coroutinized stack could differ from x86-64 -- and # a byte-exact match over a 54 kB dump of every field in nine streams is a # stronger statement about that than any hand-written assertion would be. It does # not matter that nothing on this image wrote the dump; what is being tested is # the reader. # # THE CRASH WRITER IS NOT HERE AND SECTION 2 ASSERTS IT. Breakpad's Linux client # reaches the crashing process through linux_syscall_support.h, whose entire body # sits behind an architecture guard that does not list wasm32, so the writer # cannot be compiled on this target at all -- see the bbappend. Section 2 pins # that the split really took: no libbreakpad_client.a, no client headers, none of # the ptrace-shaped tools. Those cases exist because the split is the port's main # design decision, and a later change that quietly re-enabled that arm would # otherwise show up only as a build failure in someone else's ticket. # # SECTION 6 IS WHAT MAKES SECTIONS 3-5 EVIDENCE RATHER THAN COINCIDENCE. A # byte-exact match against a reference proves nothing if the same output would # appear with the symbols removed or the input destroyed. So the same walk is run # against an EMPTY symbol directory -- which must produce unsymbolized frames and # ZERO CFI-resolved frames, where the real run has three -- and against a # truncated dump, which must be refused with no stdout at all rather than walked # into nonsense. # # NOTHING IS NORMALISED. The references carry no timestamp, no path from the # machine that made them and no address that is not in the dump itself, so unlike # cpputest's this suite filters nothing out before comparing. `tr -d '\015'` is # upstream's own step for references generated on Windows hosts and is kept so # that the comparison is character-for-character the one upstream runs. BIN=/usr/bin PT=/usr/libexec/breakpad-tests work=${TMPDIR:-/tmp}/bst-breakpad.$$ rm -rf "$work"; mkdir -p "$work" # ------------------------------------------------------------ what shipped --- check_rc breakpad/bin-minidump-dump 0 test -x "$BIN/minidump_dump" check_rc breakpad/bin-minidump-stackwalk 0 test -x "$BIN/minidump_stackwalk" check_rc breakpad/bin-microdump-stackwalk 0 test -x "$BIN/microdump_stackwalk" # The processor library is the deliverable a consumer links; breakpad-staticdev # is a separate package, so this case is what notices if the image ever installs # the binaries without it. check_rc breakpad/lib-archive 0 test -s /usr/lib/libbreakpad.a # The two headers a consumer of the processor half needs first: the on-disk # format, and the reader over it. check_rc breakpad/inc-minidump-format 0 \ test -s /usr/include/breakpad/google_breakpad/common/minidump_format.h check_rc breakpad/inc-processor-minidump 0 \ test -s /usr/include/breakpad/google_breakpad/processor/minidump.h check_rc breakpad/pkgconfig 0 test -s /usr/lib/pkgconfig/breakpad.pc # THE -dev PACKAGE MUST BE SELF-CONTAINED, and this case exists because on the # first image it was not. Upstream's Makefile.am installs the processor's # INTERNAL headers (src/processor/*.h) and has no rule at all for its PUBLIC API # (src/google_breakpad/processor/*.h) -- so 24 of the 59 installed headers named # 13 headers that were not there, and nothing could compile against # libbreakpad.a. The bbappend installs them; this asserts the CLOSURE rather than # a file list, so a future header naming a new one is caught the same way. # No compile check is possible here: this image ships no compiler. grep -rho '#include "google_breakpad/[^"]*"' /usr/include/breakpad/ 2>/dev/null \ | sed 's/.*"\(.*\)"/\1/' | sort -u > "$work/hdr-refs" refs=$(wc -l < "$work/hdr-refs" | tr -d ' ') miss=0 while read -r h; do [ -f "/usr/include/breakpad/$h" ] || miss=$((miss + 1)) done < "$work/hdr-refs" # A low floor, not the 24 measured on 2026-08-22. This case has ONE job -- to # refuse a vacuous scan, where the grep matched nothing and `miss=0` therefore # says nothing at all -- so it is set well below the measured count. Pinning it # near 24 would turn any ordinary upstream header change into a red here, which # is not what it is for. check_rc breakpad/inc-refs-nonvacuous 0 test "$refs" -ge 10 check_eq breakpad/inc-self-contained 0 "$miss" # The corpus, installed from ${S} by the same build -- so the references cannot # drift from the code that has to reproduce them. check_rc breakpad/data-dump 0 test -s "$PT/minidump2.dmp" check_rc breakpad/data-ref-dump 0 test -s "$PT/minidump2.dump.out" check_rc breakpad/data-ref-walk 0 test -s "$PT/minidump2.stackwalk.out" check_rc breakpad/data-ref-walk-mr 0 test -s "$PT/minidump2.stackwalk.machine_readable.out" check_rc breakpad/data-sym-test-app 0 \ test -s "$PT/symbols/test_app.pdb/5A9832E5287241C1838ED98914E9B7FF1/test_app.sym" check_rc breakpad/data-sym-kernel32 0 \ test -s "$PT/symbols/kernel32.pdb/BCE8785C57B44245A669896B6A19B9542/kernel32.sym" # ------------------------- 2. the split: the crash writer is NOT on this image -- # Asserted, not assumed. These are the artifacts the bbappend deliberately keeps # out; a change that re-enabled the LINUX_HOST arm would restore them, and this # is the only place on the image that would say so. check_rc breakpad/no-client-archive 1 test -e /usr/lib/libbreakpad_client.a check_rc breakpad/no-client-headers 1 test -d /usr/include/breakpad/client check_rc breakpad/no-lss-header 1 \ test -e /usr/include/breakpad/third_party/lss/linux_syscall_support.h for t in core2md pid2md minidump-2-core dump_syms sym_upload minidump_upload; do check_rc "breakpad/no-writer-tool-$t" 1 test -e "$BIN/$t" done # --------------------------------- 3. minidump_dump vs the upstream reference -- # 706 lines: the header, all nine stream directory entries, the thread list with # its full x86 CONTEXT, the module list with each module's version and debug id, the # memory list, the exception record and the system info. Every field the format # has, rendered. # # rc IS 1 ON SUCCESS AND THAT IS PINNED, NOT IGNORED. main() returns # `PrintMinidumpDump(options) ? 0 : 1`, and PrintMinidumpDump reports false when # any known stream is absent -- true of every real dump, this one included. # Upstream's minidump_dump_test checks only the stdout diff and never looks at # the status; asserting it here means a change in that behaviour is reported # rather than passing unnoticed. "$BIN/minidump_dump" "$PT/minidump2.dmp" > "$work/dump.raw" 2> "$work/dump.err"; rc=$? tr -d '\015' < "$work/dump.raw" > "$work/dump.out" check_eq breakpad/dump-rc 1 "$rc" check_rc breakpad/dump-matches-upstream 0 cmp -s "$work/dump.out" "$PT/minidump2.dump.out" # The parts, so a cmp red names the half of the reader that moved rather than # only reporting "differs". check_out breakpad/dump-stream-count "stream_count = 9" cat "$work/dump.out" check_out breakpad/dump-thread-list "(MD_THREAD_LIST_STREAM)" cat "$work/dump.out" check_out breakpad/dump-module-name '(code_file) = "c:\test_app.exe"' \ cat "$work/dump.out" check_out breakpad/dump-exception "exception_record.exception_code = 0xc0000005" \ cat "$work/dump.out" check_out breakpad/dump-sysinfo "processor_architecture = 0x0 (x86)" \ cat "$work/dump.out" check_eq breakpad/dump-line-count 706 "$(wc -l < "$work/dump.out" | tr -d ' ')" # ------------------------------- 4. minidump_stackwalk, human-readable output -- # Four frames out of a Windows crash, three of them resolved through the CFI # records in test_app.sym. This is the arm that exercises the postfix-expression # evaluator, the range maps and the .sym parser -- i.e. everything the format # reader does NOT. "$BIN/minidump_stackwalk" "$PT/minidump2.dmp" "$PT/symbols" \ > "$work/walk.raw" 2> "$work/walk.err"; rc=$? tr -d '\015' < "$work/walk.raw" > "$work/walk.out" check_eq breakpad/walk-rc 0 "$rc" check_rc breakpad/walk-matches-upstream 0 cmp -s "$work/walk.out" "$PT/minidump2.stackwalk.out" check_out breakpad/walk-os "Operating system: Windows NT" cat "$work/walk.out" check_out breakpad/walk-crash-reason "Crash reason: EXCEPTION_ACCESS_VIOLATION_WRITE" \ cat "$work/walk.out" check_out breakpad/walk-crash-addr "Crash address: 0x45" cat "$work/walk.out" # The crashing frame, symbolized down to the source line -- the single strongest # statement this suite makes, since producing it needs the dump reader, the # module lookup, the .sym parser and the line-number tables all to agree. check_out breakpad/walk-frame0-symbolized \ "::CrashFunction [test_app.cc : 58 + 0x3]" cat "$work/walk.out" check_out breakpad/walk-frame1-main "test_app.exe!main [test_app.cc : 65 + 0x5]" \ cat "$work/walk.out" check_out breakpad/walk-frame3-kernel32 "kernel32.dll!BaseProcessStart + 0x23" \ cat "$work/walk.out" check_out breakpad/walk-module-list "0x7c800000 - 0x7c8f3fff kernel32.dll 5.1.2600.2945" \ cat "$work/walk.out" # Three of the four frames are recovered from call frame information rather than # from a frame pointer. Section 6 re-runs this walk without symbols and requires # this count to be zero, which is what makes it a measurement. check_eq breakpad/walk-cfi-frames 3 \ "$(grep -c 'Found by: call frame info' "$work/walk.out" | tr -d ' ')" # ---------------------------------------- 5. the machine-readable walk (-m) ---- # A different code path in stackwalk_common.cc, and the one a crash-reporting # pipeline actually consumes. The debug ids in the Module| lines are read out of # the dump and must round-trip exactly. "$BIN/minidump_stackwalk" -m "$PT/minidump2.dmp" "$PT/symbols" \ > "$work/mr.raw" 2> "$work/mr.err"; rc=$? tr -d '\015' < "$work/mr.raw" > "$work/mr.out" check_eq breakpad/mr-rc 0 "$rc" check_rc breakpad/mr-matches-upstream 0 \ cmp -s "$work/mr.out" "$PT/minidump2.stackwalk.machine_readable.out" check_out breakpad/mr-crash-line "Crash|EXCEPTION_ACCESS_VIOLATION_WRITE|0x45|0" \ cat "$work/mr.out" check_out breakpad/mr-module-kernel32 \ "Module|kernel32.dll|5.1.2600.2945|kernel32.pdb|BCE8785C57B44245A669896B6A19B9542|0x7c800000|0x7c8f3fff|0" \ cat "$work/mr.out" check_out breakpad/mr-frame0 '|c:\test_app.cc|58|0x3' cat "$work/mr.out" check_out breakpad/mr-frame3 "0|3|kernel32.dll|BaseProcessStart|||0x23" cat "$work/mr.out" # ------------------------------------------------ 6. the controls that matter -- # Sections 3-5 compare against a fixed reference. That is only evidence if the # same output would NOT appear when the inputs are removed. # 6a. The same walk with an empty symbol directory. Frames must fall back to # module+offset and the CFI count must drop to zero -- which is what proves # the .sym files above were genuinely read rather than merely present. mkdir -p "$work/nosym" "$BIN/minidump_stackwalk" "$PT/minidump2.dmp" "$work/nosym" \ > "$work/nosym.raw" 2> "$work/nosym.err"; rc=$? tr -d '\015' < "$work/nosym.raw" > "$work/nosym.out" check_eq breakpad/nosym-rc 0 "$rc" check_rc breakpad/nosym-differs-from-symbolized 1 \ cmp -s "$work/nosym.out" "$PT/minidump2.stackwalk.out" check_out breakpad/nosym-frame0-raw "0 test_app.exe + 0x429e" cat "$work/nosym.out" check_eq breakpad/nosym-no-cfi 0 \ "$(grep -c 'Found by: call frame info' "$work/nosym.out" | tr -d ' ')" # ...and the walk still succeeds: the header, the crash reason and four frames # are recovered from the dump alone. check_out breakpad/nosym-still-walks "Crash reason: EXCEPTION_ACCESS_VIOLATION_WRITE" \ cat "$work/nosym.out" # 6b. A truncated dump is REFUSED, not walked into nonsense: rc 1, an explicit # diagnostic, and not one byte on stdout. head -c 200 "$PT/minidump2.dmp" > "$work/trunc.dmp" "$BIN/minidump_stackwalk" "$work/trunc.dmp" "$PT/symbols" \ > "$work/trunc.out" 2> "$work/trunc.err"; rc=$? check_eq breakpad/trunc-rc 1 "$rc" check_eq breakpad/trunc-no-stdout 0 "$(wc -c < "$work/trunc.out" | tr -d ' ')" check_rc breakpad/trunc-diagnostic 0 \ grep -q "MinidumpProcessor::Process failed" "$work/trunc.err" # 6c. An absent file is an error, not a crash. check_rc breakpad/absent-file-rc 1 "$BIN/minidump_dump" "$work/no-such-minidump" # 6d. microdump_stackwalk is the third program the processor arm builds. No # microdump corpus is installed (its symbol tree is 3.9 MB for one more # format), so what is asserted here is that it links and runs: invoked with # no argument it must print its own usage and refuse. "$BIN/microdump_stackwalk" > "$work/micro.out" 2> "$work/micro.err"; rc=$? check_eq breakpad/microdump-refuses-no-args 1 "$rc" check_rc breakpad/microdump-usage 0 \ grep -q "Usage: microdump_stackwalk" "$work/micro.out" "$work/micro.err" rm -rf "$work"