Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Breakpad PUBLIC symbols not resolved #37

Open
damirdev opened this issue Oct 9, 2020 · 2 comments
Open

Breakpad PUBLIC symbols not resolved #37

damirdev opened this issue Oct 9, 2020 · 2 comments

Comments

@damirdev
Copy link

damirdev commented Oct 9, 2020

Incorrect breakpad stack fixing - only functions resolved, public symbols not resolved
FileInfo

impl FileInfo {
    fn new(debug_session: ObjectDebugSession) -> FileInfo {
        // Build the `FileInfo` from the debug session.
        let mut interner = Interner::default();
        let mut func_infos: Vec<_> = debug_session
            .functions()
            .filter_map(|function| {
                let function = function.ok()?;
                Some(FuncInfo::new(&mut interner, function, 0))
            })
            .collect();
        func_infos.sort_unstable_by_key(|func_info| func_info.address);
        func_infos.dedup_by_key(|func_info| func_info.address);

        FileInfo {
            interner,
            func_infos,
        }
    }

BreakpadDebugSession<'d>

impl<'d> BreakpadDebugSession<'d> {
    /// Returns an iterator over all functions in this debug file.
    pub fn functions(&self) -> BreakpadFunctionIterator<'_> {
        BreakpadFunctionIterator {
            file_map: &self.file_map,
            func_records: self.func_records.clone(),
        }
    }

Breakpad docs:
stack_walking.md
If no match was found in the function table, another table of publicly exported symbols may be consulted (PUBLIC lines from the symbol file). Public symbols contain only a start address, so the lookup simply looks for the nearest symbol that is less than the provided RVA.

Rust-minidump

if let Some(ref func) = self.functions.get(addr) {
            frame.set_function(&func.name, func.address + module.base_address());
            // See if there's source line info as well.
            func.lines.get(addr).map(|ref line| {
                self.files.get(&line.file).map(|ref file| {
                    frame.set_source_file(file, line.line, line.address + module.base_address());
                })
            });
        } else if let Some(ref public) = self.find_nearest_public(addr) {
            // Settle for a PUBLIC.
            frame.set_function(&public.name, public.address + module.base_address());
        }
/// Find the nearest `PublicSymbol` whose address is less than or equal to `addr`.
    pub fn find_nearest_public(&self, addr: u64) -> Option<&PublicSymbol> {
        for p in self.publics.iter().rev() {
            if p.address <= addr {
                return Some(p);
            }
        }

        return None;
    }

basic_source_line_resolver.cc

void BasicSourceLineResolver::Module::LookupAddress(StackFrame *frame) const {
  MemAddr address = frame->instruction - frame->module->base_address();

  // First, look for a FUNC record that covers address. Use
  // RetrieveNearestRange instead of RetrieveRange so that, if there
  // is no such function, we can use the next function to bound the
  // extent of the PUBLIC symbol we find, below. This does mean we
  // need to check that address indeed falls within the function we
  // find; do the range comparison in an overflow-friendly way.
  linked_ptr<Function> func;
  linked_ptr<PublicSymbol> public_symbol;
  MemAddr function_base;
  MemAddr function_size;
  MemAddr public_address;
  if (functions_.RetrieveNearestRange(address, &func, &function_base,
                                      NULL /* delta */, &function_size) &&
      address >= function_base && address - function_base < function_size) {
    frame->function_name = func->name;
    frame->function_base = frame->module->base_address() + function_base;

    linked_ptr<Line> line;
    MemAddr line_base;
    if (func->lines.RetrieveRange(address, &line, &line_base, NULL /* delta */,
                                  NULL /* size */)) {
      FileMap::const_iterator it = files_.find(line->source_file_id);
      if (it != files_.end()) {
        frame->source_file_name = files_.find(line->source_file_id)->second;
      }
      frame->source_line = line->line;
      frame->source_line_base = frame->module->base_address() + line_base;
    }
  } else if (public_symbols_.Retrieve(address,
                                      &public_symbol, &public_address) &&
             (!func.get() || public_address > function_base)) {
    frame->function_name = public_symbol->name;
    frame->function_base = frame->module->base_address() + public_address;
  }
}
@nnethercote
Copy link
Contributor

Thanks for the suggestion. Does symbolic_debuginfo have a way to access the PUBLIC symbols? I can't see one, I only see the functions, files, and source_by_path methods on BreakpadDebugSession. In which case, symbolic_debuginfo will need that functionality added before fix-stacks can do this.

@damirdev
Copy link
Author

damirdev commented Oct 12, 2020

Yes, but not on BreakpadDebugSession - BreakpadObject:

pub fn symbols(&self) -> BreakpadSymbolIterator<'data> {
    BreakpadSymbolIterator {
        records: self.public_records(),
    }
}

Docs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants