Skip to content

Commit 9cb9ebd

Browse files
committed
[Backtracing][Linux] Fix crash handler for musl.
Musl's `clone()` wrapper returns `EINVAL` if you try to use `CLONE_THREAD`, which seems a bit wrong (certainly it is in this particular application, since we *really* don't care whether the thread is a valid C library thread at this point). Also properly support ELF images that are built with a base address other than zero (this typically isn't an issue for dynamically linked programs, as they will be relocated at runtime anyway, but for statically linked binaries it's very common to set the base address to a non-zero value). rdar://154282813
1 parent f5f058f commit 9cb9ebd

File tree

3 files changed

+55
-17
lines changed

3 files changed

+55
-17
lines changed

stdlib/public/RuntimeModule/Elf.swift

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1064,8 +1064,8 @@ struct ElfSymbolTable<SomeElfTraits: ElfTraits>: ElfSymbolTableProtocol {
10641064
continue
10651065
}
10661066

1067-
// Ignore anything undefined
1068-
if symbol.st_shndx == SHN_UNDEF {
1067+
// Ignore anything undefined or absolute
1068+
if symbol.st_shndx == SHN_UNDEF || symbol.st_shndx == SHN_ABS {
10691069
continue
10701070
}
10711071

@@ -1190,6 +1190,8 @@ final class ElfImage<SomeElfTraits: ElfTraits>
11901190
var sectionHeaders: [Traits.Shdr]?
11911191
var shouldByteSwap: Bool { return header.shouldByteSwap }
11921192

1193+
var imageBase: ImageSource.Address
1194+
11931195
@_specialize(kind: full, where SomeElfTraits == Elf32Traits)
11941196
@_specialize(kind: full, where SomeElfTraits == Elf64Traits)
11951197
required init(source: ImageSource,
@@ -1222,11 +1224,21 @@ final class ElfImage<SomeElfTraits: ElfTraits>
12221224

12231225
var phdrs: [Traits.Phdr] = []
12241226
var phAddr = ImageSource.Address(header.e_phoff)
1227+
var minAddr: Traits.Address? = nil
12251228
for _ in 0..<header.e_phnum {
12261229
let phdr = maybeSwap(try source.fetch(from: phAddr, as: Traits.Phdr.self))
12271230
phdrs.append(phdr)
12281231
phAddr += ImageSource.Address(header.e_phentsize)
1232+
1233+
if phdr.p_type == .PT_LOAD {
1234+
if let oldMinAddr = minAddr {
1235+
minAddr = min(oldMinAddr, phdr.p_vaddr)
1236+
} else {
1237+
minAddr = phdr.p_vaddr
1238+
}
1239+
}
12291240
}
1241+
imageBase = ImageSource.Address(exactly: minAddr ?? 0)!
12301242
programHeaders = phdrs
12311243

12321244
if source.isMappedImage {

stdlib/public/RuntimeModule/SymbolicatedBacktrace.swift

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -466,9 +466,6 @@ public struct SymbolicatedBacktrace: CustomStringConvertible {
466466
for frame in backtrace.frames {
467467
let address = frame.adjustedProgramCounter
468468
if let imageNdx = theImages.indexOfImage(at: address) {
469-
let relativeAddress = ImageSource.Address(
470-
address - theImages[imageNdx].baseAddress
471-
)
472469
let name = theImages[imageNdx].name ?? "<unknown>"
473470
var symbol: Symbol = Symbol(imageIndex: imageNdx,
474471
imageName: name,
@@ -527,13 +524,19 @@ public struct SymbolicatedBacktrace: CustomStringConvertible {
527524
if let hit = cache.lookup(path: theImages[imageNdx].path) {
528525
switch hit {
529526
case let .elf32Image(image):
527+
let relativeAddress = ImageSource.Address(
528+
address - theImages[imageNdx].baseAddress
529+
) + image.imageBase
530530
if let theSymbol = lookupSymbol(image: image,
531531
at: imageNdx,
532532
named: name,
533533
address: relativeAddress) {
534534
symbol = theSymbol
535535
}
536536
case let .elf64Image(image):
537+
let relativeAddress = ImageSource.Address(
538+
address - theImages[imageNdx].baseAddress
539+
) + image.imageBase
537540
if let theSymbol = lookupSymbol(image: image,
538541
at: imageNdx,
539542
named: name,

stdlib/public/runtime/CrashHandlerLinux.cpp

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,15 @@
4949
#include <string.h>
5050
#include <unistd.h>
5151

52+
#define DEBUG_MEMSERVER 0
53+
54+
#if DEBUG_MEMSERVER
55+
#include <stdio.h>
56+
#define memserver_error(x) perror(x)
57+
#else
58+
#define memserver_error(x)
59+
#endif
60+
5261
#include "swift/Runtime/Backtrace.h"
5362

5463
#include <cstring>
@@ -86,8 +95,8 @@ ssize_t safe_read(int fd, void *buf, size_t len) {
8695
ssize_t ret;
8796
do {
8897
ret = read(fd, buf, len);
89-
} while (ret < 0 && errno == EINTR);
90-
if (ret < 0)
98+
} while (ret <= 0 && errno == EINTR);
99+
if (ret <= 0)
91100
return ret;
92101
total += ret;
93102
ptr += ret;
@@ -106,8 +115,8 @@ ssize_t safe_write(int fd, const void *buf, size_t len) {
106115
ssize_t ret;
107116
do {
108117
ret = write(fd, buf, len);
109-
} while (ret < 0 && errno == EINTR);
110-
if (ret < 0)
118+
} while (ret <= 0 && errno == EINTR);
119+
if (ret <= 0)
111120
return ret;
112121
total += ret;
113122
ptr += ret;
@@ -657,20 +666,28 @@ memserver_start()
657666
int fds[2];
658667

659668
ret = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
660-
if (ret < 0)
669+
if (ret < 0) {
670+
memserver_error("memserver_start: socketpair failed");
661671
return ret;
672+
}
662673

663674
memserver_fd = fds[0];
664675
ret = clone(memserver_entry, memserver_stack + sizeof(memserver_stack),
665676
#if MEMSERVER_USE_PROCESS
666677
0,
667678
#else
668-
CLONE_THREAD | CLONE_VM | CLONE_FILES
669-
| CLONE_FS | CLONE_IO | CLONE_SIGHAND,
679+
#ifndef __musl__
680+
// Can't use CLONE_THREAD on musl because the clone() function
681+
// there returns EINVAL if we do.
682+
CLONE_THREAD | CLONE_SIGHAND |
683+
#endif
684+
CLONE_VM | CLONE_FILES | CLONE_FS | CLONE_IO,
670685
#endif
671686
NULL);
672-
if (ret < 0)
687+
if (ret < 0) {
688+
memserver_error("memserver_start: clone failed");
673689
return ret;
690+
}
674691

675692
#if MEMSERVER_USE_PROCESS
676693
memserver_pid = ret;
@@ -718,7 +735,7 @@ memserver_entry(void *dummy __attribute__((unused))) {
718735
int fd = memserver_fd;
719736
int result = 1;
720737

721-
#if MEMSERVER_USE_PROCESS
738+
#if MEMSERVER_USE_PROCESS || defined(__musl__)
722739
prctl(PR_SET_NAME, "[backtrace]");
723740
#endif
724741

@@ -743,8 +760,10 @@ memserver_entry(void *dummy __attribute__((unused))) {
743760
ssize_t ret;
744761

745762
ret = safe_read(fd, &req, sizeof(req));
746-
if (ret != sizeof(req))
763+
if (ret != sizeof(req)) {
764+
memserver_error("memserver: terminating because safe_read() returned wrong size");
747765
break;
766+
}
748767

749768
uint64_t addr = req.addr;
750769
uint64_t bytes = req.len;
@@ -761,15 +780,19 @@ memserver_entry(void *dummy __attribute__((unused))) {
761780
resp.len = ret;
762781

763782
ret = safe_write(fd, &resp, sizeof(resp));
764-
if (ret != sizeof(resp))
783+
if (ret != sizeof(resp)) {
784+
memserver_error("memserver: terminating because safe_write() failed");
765785
goto fail;
786+
}
766787

767788
if (resp.len < 0)
768789
break;
769790

770791
ret = safe_write(fd, memserver_buffer, resp.len);
771-
if (ret != resp.len)
792+
if (ret != resp.len) {
793+
memserver_error("memserver: terminating because safe_write() failed (2)");
772794
goto fail;
795+
}
773796

774797
addr += resp.len;
775798
bytes -= resp.len;

0 commit comments

Comments
 (0)