| Index: base/third_party/symbolize/symbolize.cc
|
| diff --git a/base/third_party/symbolize/symbolize.cc b/base/third_party/symbolize/symbolize.cc
|
| index db82b04d4df254a345107f532c636511cc5e6753..02500c35f5910164d5bf7b783664b42b3329859c 100644
|
| --- a/base/third_party/symbolize/symbolize.cc
|
| +++ b/base/third_party/symbolize/symbolize.cc
|
| @@ -404,7 +404,7 @@ class LineReader {
|
| //
|
| // Note: if the last line doesn't end with '\n', the line will be
|
| // dropped. It's an intentional behavior to make the code simple.
|
| - bool ReadLine(const char **bol, const char **eol) {
|
| + bool ReadLine(char **bol, char **eol) {
|
| if (BufferIsEmpty()) { // First time.
|
| const ssize_t num_bytes = ReadPersistent(fd_, buf_, buf_len_);
|
| if (num_bytes <= 0) { // EOF or error.
|
| @@ -443,12 +443,12 @@ class LineReader {
|
| }
|
|
|
| // Beginning of line.
|
| - const char *bol() {
|
| + char *bol() {
|
| return bol_;
|
| }
|
|
|
| // End of line.
|
| - const char *eol() {
|
| + char *eol() {
|
| return eol_;
|
| }
|
|
|
| @@ -509,95 +509,141 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
|
| uint64_t &base_address,
|
| char *out_file_name,
|
| int out_file_name_size) {
|
| - int object_fd;
|
| + struct FindArgs {
|
| + const uint64_t pc;
|
| + uint64_t* out_start_address;
|
| + uint64_t* out_base_address;
|
| + char* out_file_name;
|
| + int out_file_name_size;
|
| + // Fields below are default initialized
|
| + int num_maps;
|
| + int out_object_fd;
|
| + };
|
| +
|
| + auto find_callback = [](void* data, const MappedRegion& region) -> bool {
|
| + FindArgs* args = static_cast<FindArgs*>(data);
|
| + args->num_maps++;
|
|
|
| + // Check start and end addresses.
|
| + if (!(region.start_address <= args->pc && args->pc < region.end_address)) {
|
| + return false; // We skip this map. PC isn't in this map.
|
| + }
|
| +
|
| + // Check flags. We are only interested in "r-x" maps.
|
| + if (memcmp(region.flags, "r-x", 3) != 0) { // Not a "r-x" map.
|
| + return false; // We skip this map.
|
| + }
|
| +
|
| + *args->out_start_address = region.start_address;
|
| +
|
| + // Don't subtract 'start_address' from the first entry:
|
| + // * If a binary is compiled w/o -pie, then the first entry in
|
| + // process maps is likely the binary itself (all dynamic libs
|
| + // are mapped higher in address space). For such a binary,
|
| + // instruction offset in binary coincides with the actual
|
| + // instruction address in virtual memory (as code section
|
| + // is mapped to a fixed memory range).
|
| + // * If a binary is compiled with -pie, all the modules are
|
| + // mapped high at address space (in particular, higher than
|
| + // shadow memory of the tool), so the module can't be the
|
| + // first entry.
|
| + *args->out_base_address =
|
| + ((args->num_maps == 1) ? 0U : region.start_address) -
|
| + region.file_offset;
|
| +
|
| + // Open region's file.
|
| + NO_INTR(args->out_object_fd = open(region.name, O_RDONLY));
|
| + if (args->out_object_fd < 0) {
|
| + // Failed to open object file. Copy the object file name to
|
| + // |out_file_name|.
|
| + strncpy(args->out_file_name, region.name, args->out_file_name_size);
|
| + // Making sure |out_file_name| is always null-terminated.
|
| + args->out_file_name[args->out_file_name_size - 1] = '\0';
|
| + }
|
| +
|
| + return true; // We found the entry; stop iterating.
|
| + };
|
| +
|
| + FindArgs args = {
|
| + pc,
|
| + &start_address,
|
| + &base_address,
|
| + out_file_name,
|
| + out_file_name_size
|
| + };
|
| + bool found = FindMappedRegion(&args, find_callback);
|
| + return found ? args.out_object_fd : -1;
|
| +}
|
| +
|
| +bool FindMappedRegion(void* callback_data,
|
| + bool (*callback)(void*, const MappedRegion&)) {
|
| // Open /proc/self/maps.
|
| int maps_fd;
|
| NO_INTR(maps_fd = open("/proc/self/maps", O_RDONLY));
|
| FileDescriptor wrapped_maps_fd(maps_fd);
|
| if (wrapped_maps_fd.get() < 0) {
|
| - return -1;
|
| + return false;
|
| }
|
|
|
| - // Iterate over maps and look for the map containing the pc. Then
|
| - // look into the symbol tables inside.
|
| char buf[1024]; // Big enough for line of sane /proc/self/maps
|
| int num_maps = 0;
|
| + MappedRegion region;
|
| LineReader reader(wrapped_maps_fd.get(), buf, sizeof(buf));
|
| while (true) {
|
| num_maps++;
|
| - const char *cursor;
|
| - const char *eol;
|
| + char *cursor;
|
| + char *eol;
|
| if (!reader.ReadLine(&cursor, &eol)) { // EOF or malformed line.
|
| - return -1;
|
| + break;
|
| }
|
|
|
| + // Zero-terminate the line.
|
| + *eol = 0;
|
| +
|
| // Start parsing line in /proc/self/maps. Here is an example:
|
| //
|
| // 08048000-0804c000 r-xp 00000000 08:01 2142121 /bin/cat
|
| //
|
| // We want start address (08048000), end address (0804c000), flags
|
| - // (r-xp) and file name (/bin/cat).
|
| + // (r-xp), file offset (2142121) and file name (/bin/cat).
|
|
|
| // Read start address.
|
| - cursor = GetHex(cursor, eol, &start_address);
|
| + cursor = GetHex(cursor, eol, ®ion.start_address);
|
| if (cursor == eol || *cursor != '-') {
|
| - return -1; // Malformed line.
|
| + break; // Malformed line.
|
| }
|
| ++cursor; // Skip '-'.
|
|
|
| // Read end address.
|
| uint64_t end_address;
|
| - cursor = GetHex(cursor, eol, &end_address);
|
| + cursor = GetHex(cursor, eol, ®ion.end_address);
|
| if (cursor == eol || *cursor != ' ') {
|
| - return -1; // Malformed line.
|
| + break; // Malformed line.
|
| }
|
| ++cursor; // Skip ' '.
|
|
|
| - // Check start and end addresses.
|
| - if (!(start_address <= pc && pc < end_address)) {
|
| - continue; // We skip this map. PC isn't in this map.
|
| - }
|
| -
|
| // Read flags. Skip flags until we encounter a space or eol.
|
| - const char * const flags_start = cursor;
|
| + region.flags = cursor;
|
| while (cursor < eol && *cursor != ' ') {
|
| ++cursor;
|
| }
|
| // We expect at least four letters for flags (ex. "r-xp").
|
| - if (cursor == eol || cursor < flags_start + 4) {
|
| - return -1; // Malformed line.
|
| + if (cursor == eol || cursor < region.flags + 4) {
|
| + break; // Malformed line.
|
| }
|
| -
|
| - // Check flags. We are only interested in "r-x" maps.
|
| - if (memcmp(flags_start, "r-x", 3) != 0) { // Not a "r-x" map.
|
| - continue; // We skip this map.
|
| - }
|
| - ++cursor; // Skip ' '.
|
| + // Replace ' ' with zero and advance.
|
| + *cursor++ = 0;
|
|
|
| // Read file offset.
|
| - uint64_t file_offset;
|
| - cursor = GetHex(cursor, eol, &file_offset);
|
| + cursor = GetHex(cursor, eol, ®ion.file_offset);
|
| if (cursor == eol || *cursor != ' ') {
|
| - return -1; // Malformed line.
|
| + break; // Malformed line.
|
| }
|
| ++cursor; // Skip ' '.
|
|
|
| - // Don't subtract 'start_address' from the first entry:
|
| - // * If a binary is compiled w/o -pie, then the first entry in
|
| - // process maps is likely the binary itself (all dynamic libs
|
| - // are mapped higher in address space). For such a binary,
|
| - // instruction offset in binary coincides with the actual
|
| - // instruction address in virtual memory (as code section
|
| - // is mapped to a fixed memory range).
|
| - // * If a binary is compiled with -pie, all the modules are
|
| - // mapped high at address space (in particular, higher than
|
| - // shadow memory of the tool), so the module can't be the
|
| - // first entry.
|
| - base_address = ((num_maps == 1) ? 0U : start_address) - file_offset;
|
| -
|
| // Skip to file name. "cursor" now points to dev. We need to
|
| - // skip at least two spaces for dev and inode.
|
| + // skip at least two spaces for dev and inode. Note that name can
|
| + // be empty (cursor == eol).
|
| int num_spaces = 0;
|
| while (cursor < eol) {
|
| if (*cursor == ' ') {
|
| @@ -609,22 +655,17 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
|
| }
|
| ++cursor;
|
| }
|
| - if (cursor == eol) {
|
| - return -1; // Malformed line.
|
| - }
|
|
|
| - // Finally, "cursor" now points to file name of our interest.
|
| - NO_INTR(object_fd = open(cursor, O_RDONLY));
|
| - if (object_fd < 0) {
|
| - // Failed to open object file. Copy the object file name to
|
| - // |out_file_name|.
|
| - strncpy(out_file_name, cursor, out_file_name_size);
|
| - // Making sure |out_file_name| is always null-terminated.
|
| - out_file_name[out_file_name_size - 1] = '\0';
|
| - return -1;
|
| + // Finally, "cursor" now points to file name.
|
| + region.name = cursor;
|
| +
|
| + // Report found region to the callback.
|
| + if (callback(callback_data, region)) {
|
| + return true; // Callback stopped the iteration.
|
| }
|
| - return object_fd;
|
| }
|
| +
|
| + return false;
|
| }
|
|
|
| // POSIX doesn't define any async-signal safe function for converting
|
|
|