Пример #1
0
func (p *appleParser) parseBinaryImages(startIndex int) error {
	p.modules = make(map[string]binaryImage)
	for _, line := range p.lines[startIndex:] {
		// Stop at the first line which is blank or starts with "Sample analysis of
		// process [<process ID> written]", which indicates the end of the section.
		if line == "" || strings.HasPrefix(line, kSampleAnalysisWritten) {
			break
		}

		matches := kBinaryImage.FindAllStringSubmatch(line, -1)
		if matches == nil || len(matches) != 1 {
			return fmt.Errorf("invalid binary image: %s", line)
		}

		image := binaryImage{
			name:  matches[0][2],
			ident: matches[0][3],
			path:  matches[0][4],
		}
		var err error
		image.baseAddress, err = breakpad.ParseAddress(matches[0][1])
		if err != nil {
			return fmt.Errorf("parse binary image: %v", err)
		}
		p.modules[image.name] = image
	}
	return nil
}
Пример #2
0
func (p *appleParser) Symbolize(tables []breakpad.SymbolTable) string {
	if p.lineParser == nil {
		panic(fmt.Sprintf("Cannot handle report version %d", p.reportVersion))
	}

	tableMap := p.mapTables(tables)

	// The p.modules is mapped by bundle ID, so re-map it to be done by breakpad
	// name.
	var modules map[string]binaryImage
	if p.tableMapType == kModuleTypeBreakpad {
		modules = make(map[string]binaryImage, len(p.modules))
		for _, module := range p.modules {
			modules[module.breakpadName()] = module
		}
	}

	for i, line := range p.lines {
		frag := p.lineParser(line)
		if frag == nil {
			continue
		}

		address, err := breakpad.ParseAddress(line[frag.address[0]:frag.address[1]])
		if err != nil {
			continue
		}

		var binaryImage binaryImage
		moduleName := line[frag.module[0]:frag.module[1]]
		if p.tableMapType == kModuleTypeBreakpad {
			var ok bool
			binaryImage, ok = modules[moduleName]
			if !ok {
				continue
			}
		} else {
			binaryImage = p.modules[moduleName]
		}

		table, ok := tableMap[binaryImage.breakpadName()]
		if !ok {
			continue
		}
		symbol := table.SymbolForAddress(address - binaryImage.baseAddress)

		rl := replacementList{
			{loc: frag.functionName, value: symbol.Function},
			{loc: frag.fileNameLocation, value: symbol.FileLine()},
		}
		sort.Sort(sort.Reverse(rl))
		for _, r := range rl {
			start, end := r.loc[0], r.loc[1]
			p.lines[i] = p.lines[i][:start] + r.value + p.lines[i][end:]
		}
	}

	return strings.Join(p.lines, "\n")
}
Пример #3
0
func (p *fragmentParser) parseAddresses(gip *GeneratorParser, input string) error {
	addresses := strings.Fields(input)
	for _, address := range addresses {
		absAddress, err := breakpad.ParseAddress(address)
		if err != nil {
			gip.EmitStackFrame(0, GIPStackFrame{Placeholder: address})
		} else {
			gip.EmitStackFrame(0, GIPStackFrame{
				RawAddress: absAddress,
				Address:    absAddress - p.baseAddress,
				Module:     p.module,
			})
		}
	}
	return nil
}
Пример #4
0
// handleFragment extracts fragment-specific input from the HTTP request and
// returns a FragmentParser if successful.
func (h *Handler) handleFragment(ctx context.Context, rw http.ResponseWriter, req *http.Request) parser.Parser {
	module := req.FormValue("module")
	ident := req.FormValue("ident")
	if module == "" || ident == "" {
		replyError(req, rw, http.StatusBadRequest, "Missing module or ident")
		return nil
	}

	loadAddress, err := breakpad.ParseAddress(req.FormValue("load_address"))
	if err != nil {
		replyError(req, rw, http.StatusBadRequest, fmt.Sprintf("Load address: %s", err))
		return nil
	}

	return parser.NewFragmentParser(module, ident, loadAddress)
}
Пример #5
0
func main() {
	flag.Parse()

	if *symbolFile == "" {
		fatal("Need to specify a symbol file")
	}
	offset, err := breakpad.ParseAddress(*baseAddress)
	if err != nil {
		fatal(err)
	}

	fd, err := os.Open(*symbolFile)
	if err != nil {
		fatal(err)
	}
	defer fd.Close()

	data, err := ioutil.ReadAll(fd)
	if err != nil {
		fatal(err)
	}

	table, err := breakpad.NewBreakpadSymbolTable(string(data))
	if err != nil {
		fatal(err)
	}

	input := strings.Join(flag.Args(), " ")

	parser := parser.NewFragmentParser(table.ModuleName(), table.Identifier(), offset)
	if err = parser.ParseInput(input); err != nil {
		fatal(err)
	}

	fmt.Println(parser.Symbolize([]breakpad.SymbolTable{table}))
}
Пример #6
0
// buildGenParser performs two steps: 1) parse stack frames from the given input;
// 2) parse out the build version number, which we use to locate a module n the crash
// server.   The parser is derived from clank/tools/stack_core.py.  Once these two steps
// have been completed, this function returns a GeneratorParser, which encapsultes
// the infor parsed in these two steps and help to format the output in Symbolize.
func (p *androidParser) buildGenParser(lines []string) (*GeneratorParser, error) {
	// An example of a line of logcat frame:
	// "0I/DEBUG   ( 2636):     #23  pc 0002b5ec  /system/lib/libdvm.so (dvmInterpret(Thread*, Method const*, JValue*)+184)"
	frameLine := regexp.MustCompile("(.*)\\#([0-9]+)[ \t]+(..)[ \t]+([0-9a-f]{8})[ \t]+([^\r\n \t]*)( \\((.*)\\))?")
	// An example of the version number (format 0):
	// "W/google-breakpad(27887): 27.0.1453.105".
	version0Line := regexp.MustCompile("google\\-breakpad(?:\\([0-9]+\\))*: (([0-9]+\\.)+[0-9]+)$")
	// An example of the version number (format 1):
	// "W/google-breakpad(27887): 1453106".
	version1Line := regexp.MustCompile("google\\-breakpad(?:\\([0-9]+\\))*: (([0-9]+\\.)*[0-9]+)$")

	// Keep track of the android chrome version for crash server look-up.
	var version string

	// Keep track of the frames we read in the input.
	frames := make([]androidFrame, 0, len(lines))

	for _, line := range lines {
		// Parse out the version number of this android chrome build.
		if version0Line.MatchString(line) {
			match := version0Line.FindStringSubmatch(line)
			version = match[1]
		} else if version1Line.MatchString(line) && version == "" {
			match := version1Line.FindStringSubmatch(line)
			version = match[1]
		} else if frameLine.MatchString(line) {
			// Parse out a single frame.
			match := frameLine.FindStringSubmatch(line)

			if fnum, err := strconv.ParseUint(match[2], 10, 0); err == nil {
				// ParseAddress cannot fail if the regular expression passes
				addr, _ := breakpad.ParseAddress(match[4])
				frames = append(frames, androidFrame{
					module:      match[5],
					address:     addr,
					frameNumber: uint(fnum),
					symbol:      match[7],
				})
			} else {
				return nil, fmt.Errorf("Failed to parse the frame number %s in line: %s", match[2], line)
			}
		}
	}

	// If a version was given as manual input.  The manual version number supersedes the version in the log.
	if p.version != "" {
		version = p.version
	}

	// Check here to see we found the version number in the log.
	if version == "" {
		return nil, errors.New("Version number of Chrome was not found.")
	}

	// Use the version number to retrieve the chrome module (libchromeview.so).
	if chromeViewModule, err := p.retrieveChromeModule(version); err == nil {
		// Create a GeneratorParser.  For every libchromeview symbol, we emit a proper stack frame.
		// For other frames, we store the given module and symbol name as the place holder; they will
		// show up in the final output.
		retparser := NewGeneratorParser(func(parser *GeneratorParser, input string) error {
			for _, frame := range frames {
				if strings.HasSuffix(frame.module, "libchromeview.so") {
					parser.EmitStackFrame(0, GIPStackFrame{
						RawAddress: frame.address,
						Address:    frame.address,
						Module:     chromeViewModule,
					})
				} else {
					parser.EmitStackFrame(0, GIPStackFrame{
						RawAddress:  frame.address,
						Address:     frame.address,
						Placeholder: "[" + frame.module + "] " + frame.symbol,
					})
				}
			}
			return nil
		})

		return retparser, nil
	} else {
		return nil, err
	}
}
Пример #7
0
func (p *stackwalkParser) ParseInput(data string) error {
	buf := bytes.NewBufferString(data)

	parsingThreads := false
	for {
		// Read the input string a line at a time.
		line, err := buf.ReadString('\n')
		if err != nil {
			if err == io.EOF {
				return nil
			} else {
				return err
			}
		}
		line = line[0 : len(line)-1] // Remove \n.

		// There is only one blank line in the input: the separator between the
		// metadata and the thread list.
		if line == "" {
			if !parsingThreads {
				parsingThreads = true
				continue
			} else {
				return errors.New("unexpected blank line: already encountered thread list")
			}
		}

		fields := strings.Split(line, "|")

		if parsingThreads {
			if len(fields) < kStackwalkFrame_Len {
				return fieldError("stack frame", kStackwalkFrame_Len, len(fields), line)
			}
			// Extract the thread ID from the frame and create a new thread
			// slice if it is a new thread.
			threadId, err := strconv.Atoi(fields[kStackwalkFrameThread])
			if err != nil {
				return err
			}

			// Create the frame information.
			address, err := breakpad.ParseAddress(fields[kStackwalkFrameAddress])
			if err != nil {
				return err
			}
			module := fields[kStackwalkFrameModule]
			p.threads[threadId] = append(p.threads[threadId], stackwalkFrame{
				module:  module,
				address: address,
			})
			if module != "" {
				p.usedModules[module] = true
			}
		} else {
			switch fields[0] {
			case kStackwalkCrash:
				if len(fields) < kStackwalkCrash_Len {
					return fieldError("crash line", kStackwalkCrash_Len, len(fields), line)
				}
				p.crashInfo = fields[1] + " @ " + fields[2]
				crashedThread, err := strconv.Atoi(fields[3])
				if err != nil {
					return err
				}
				p.crashedThread = crashedThread
			case kStackwalkModule:
				if len(fields) < kStackwalkModule_Len {
					return fieldError("module", kStackwalkFrame_Len, len(fields), line)
				}
				name := fields[kStackwalkModuleName]
				p.modules[name] = fields[kStackwalkModuleIdentifier]
			}
		}
	}
}